使用Envoy代替Nginx作为反向代理服务
介绍
Envoy 是一个由 Lyft 开发并开源的高性能、可扩展的服务代理,属于 “Service Mesh” 领域。它主要用作反向代理、负载均衡器和 API 网关,但其灵活的架构使其也可以用于其他用途。Envoy 设计之初的目标就是为云原生应用提供更加智能的网络通信能力。Envoy 相比 Nginx 的优势如下:
云原生设计
- Envoy:专为微服务架构设计,具有丰富的动态配置能力,适用于云原生环境和 Kubernetes 中的服务网格。
- Nginx:虽然可以在微服务环境中使用,但最初并不是为云原生设计的,动态配置和服务发现能力相对较弱。
动态配置
- Envoy:支持动态配置更新,无需重启即可应用新配置,减少了服务中断的风险。
- Nginx:虽然支持某些程度的热加载,但大部分配置更新依然需要重启服务,导致短暂的服务中断。
Service Mesh 支持
- Envoy:是许多 Service Mesh 解决方案(如 Istio)的核心数据平面代理,提供先进的流量管理功能,如熔断、限流、负载均衡和故障注入。
- Nginx:虽然可以通过 Lua 脚本等方式实现某些功能,但不如 Envoy 集成得那么深入和简便。
高级协议支持
- Envoy:支持 HTTP/1.1、HTTP/2 和 gRPC 的高级负载均衡和代理能力,还提供了全面的流量管理功能。
- Nginx:也支持这些协议,但在 gRPC 和 HTTP/2 处理方面,Envoy 更加灵活和高效。
可观测性
- Envoy:提供了全面的可观测性,包括分布式追踪、详细的统计数据、日志和指标,这些对于微服务架构中的故障排查和性能优化非常有帮助。
- Nginx:虽然也提供日志和基本的指标收集,但在分布式追踪和深入的指标收集上,Envoy 更加强大。
扩展性
- Envoy:设计为高度可扩展和可编程,支持通过插件扩展其功能,特别适合复杂的微服务架构。
- Nginx:虽然也有丰富的模块化支持,但其扩展能力和动态配置的灵活性不如 Envoy。
多协议支持
- Envoy:不仅支持 HTTP,还支持 TCP、UDP、gRPC、Redis 等多种协议的代理,适应性更强。
- Nginx:主要针对 HTTP,但也支持 TCP 和 UDP,不过 Envoy 的多协议支持更加全面和灵活。
安装Envoy
笔者的项目最早使用Nginx作为反向代理服务,为了在反向代理连接中利用multiplexing,决定将应用服务器的协议升级到HTTP2,但是Nginx的反向代理只支持HTTP1.1,在经过一系列调研后,决定使用Envoy替换掉Nginx作为新的反向代理服务。
笔者的服务器系统为ubuntu 22.04 LTS,可以直接在Envoy官网下载二进制包,下载链接,目前最新版本为1.33.0,下载后得到名为envoy-1.33.0-linux-x86_64的文件,将该文件放到/usr/local/bin下并改名为envoy:
$ sudo cp envoy-1.33.0-linux-x86_64 /usr/local/bin/envoy
$ sudo chmod 777 /usr/local/bin/envoy
2
可以查看一下envoy的版本:
$ sudo envoy --version
envoy version: 7b8baff1758f0a584dcc3cb657b5032000bcb3d7/1.31.0/Clean/RELEASE/BoringSSL
2
配置Envoy
为便于管理,我们可以将envoy配置为systemd
服务,创建文件/etc/systemd/system/envoy.service
,编辑内容如下:
[Unit]
Description=Envoy Proxy
After=network.target
[Service]
ExecStart=/usr/local/bin/envoy -l debug -c /etc/envoy/envoy.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
LimitNOFILE=1048576
LimitNPROC=1048576
TimeoutStartSec=0
StartLimitBurst=3
StartLimitInterval=60s
TasksMax=infinity
User=root
Group=root
[Install]
WantedBy=multi-user.target
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
从服务配置中可以看到envoy自身的配置文件应位于/etc/envoy/envoy.yaml
,我们稍后进行配置,首先了解下服务的整体架构:
- envoy安装在192.168.3.31,监听80和443端口
- 应用服务器1位于192.168.3.32,监听8443端口
- 应用服务器2位于192.168.3.33,监听8443端口
证书的创建以及应用服务器的HTTP2协议配置过程不在此赘述,假设envoy和应用服务的证书已经配置好,编辑配置文件/etc/envoy/envoy.yaml
如下:
# 管理员控制台的相关配置
admin:
access_log_path: "/var/log/envoy/admin_access.log"
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
# 为80端口创建一个监听器
- name: main_listener_http
address:
socket_address:
address: 0.0.0.0
port_value: 80
per_connection_buffer_limit_bytes: 32768 # 每个连接的缓存大小限制在32 KiB
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
use_remote_address: true
normalize_path: true
merge_slashes: true
path_with_escaped_slashes_action: UNESCAPE_AND_REDIRECT
common_http_protocol_options:
idle_timeout: 3600s
headers_with_underscores_action: REJECT_REQUEST
stream_idle_timeout: 300s
request_timeout: 300s
generate_request_id: false
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/var/log/envoy/access.log"
log_format: # 访问日志格式与nginx相同,便于迁移
text_format: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% - - [%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %BYTES_SENT% \"%REQ(REFERER)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-FORWARDED-FOR)%\"\n"
route_config:
name: local_route
request_headers_to_add:
- header:
key: X-Client-IP
value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
- header:
key: X-Proxy
value: "envoy"
- header:
key: X-Request-Start
value: "%START_TIME(%s.%3f)%"
virtual_hosts:
- name: backend
domains:
- "192.168.3.31:80" # 该域名下的请求匹配当前路由规则
routes:
- match:
prefix: "/"
redirect: # 所有http请求重定向为https
scheme_redirect: "https"
port_redirect: 443
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
# 为443端口创建一个监听器
- name: main_listener_https
address:
socket_address:
address: 0.0.0.0
port_value: 443
listener_filters:
- name: "envoy.filters.listener.tls_inspector"
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
per_connection_buffer_limit_bytes: 32768 # 每个连接的缓存大小限制在32 KiB
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
use_remote_address: true
normalize_path: true
merge_slashes: true
path_with_escaped_slashes_action: UNESCAPE_AND_REDIRECT
common_http_protocol_options:
idle_timeout: 3600s
headers_with_underscores_action: REJECT_REQUEST
http2_protocol_options:
max_concurrent_streams: 100
initial_stream_window_size: 65536
initial_connection_window_size: 1048576
stream_idle_timeout: 300s
request_timeout: 300s
generate_request_id: false
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/var/log/envoy/access.log"
log_format: # 访问日志格式与nginx相同,便于迁移
text_format: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% - - [%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %BYTES_SENT% \"%REQ(REFERER)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-FORWARDED-FOR)%\"\n"
route_config:
name: local_route
request_headers_to_add:
- header:
key: X-Client-IP
value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
- header:
key: X-Proxy
value: "envoy"
- header:
key: X-Request-Start
value: "%START_TIME(%s.%3f)%"
virtual_hosts:
- name: backend
domains:
- "192.168.3.31:443"
routes:
- match:
prefix: "/"
route:
cluster: service # 将请求代理到service集群
max_stream_duration:
max_stream_duration: 0s
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
# envoy证书配置
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
alpn_protocols: ["h2", "http/1.1"]
tls_certificates:
- certificate_chain:
filename: "/etc/envoy/cert/server.pem"
private_key:
filename: "/etc/envoy/cert/server.key"
clusters:
# 后端集群配置
- name: service # 名为service的代理集群,与route_config中配置的一致
per_connection_buffer_limit_bytes: 32768 # 每个连接的缓存大小限制在32 KiB
type: STRICT_DNS
load_assignment:
cluster_name: service
endpoints: # 两个后端服务器配置
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.3.32
port_value: 8443
- endpoint:
address:
socket_address:
address: 192.168.3.33
port_value: 8443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
alpn_protocols: ["h2", "http/1.1"]
# http2相关配置
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options:
initial_stream_window_size: 65536 # 64 KiB
initial_connection_window_size: 1048576 # 1 MiB
overload_manager:
resource_monitors:
- name: envoy.resource_monitors.global_downstream_max_connections
typed_config:
"@type": type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig
max_active_downstream_connections: 50000
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
编辑完毕后,启动envoy服务:
$ sudo systemctl start envoy
现在可以通过浏览器在443端口访问服务了,并且可以通过Chrome中的开发人员工具看到请求均使用http2协议,除此之外可以在后端应用服务处理请求时打印协议版本号,也可以发现从envoy向应用服务器发送的请求也使用http2协议。
其他
由于Envoy官方并未提供日志切分压缩功能,因此需要使用logrotate工具处理,先确认下logrotate是否在cron任务中:
sudo vi /etc/cron.daily/logrotate
然后创建文件/etc/logrotate.d/envoy,内容如下:
/var/log/envoy/access.log {
daily
rotate 7
missingok
compress
notifempty
nocreate
sharedscripts
copytruncate
}
2
3
4
5
6
7
8
9
10
该配置对envoy的访问日志/var/log/envoy/access.log进行切分并压缩,且只保留7天内的日志
为什么
你觉得为什么它能击败Nginx以及HAProxy等竞品,成为Service Mesh体系核心?
Envoy 是由 Lyft 开发并开源的一款高性能开源代理,近年来迅速成为 Service Mesh 体系的核心组件之一。它之所以能够击败 Nginx 和 HAProxy 等竞品,成为众多微服务架构中的首选,有以下几个主要原因:
设计现代化
- 初始设计即为云原生和微服务:Envoy 从一开始就设计为服务代理,专注于服务间通信的复杂性,而不是像 Nginx 和 HAProxy 那样起源于传统的 L7 代理和负载均衡。
- 面向分布式系统:Envoy 的设计考虑了现代分布式系统的需求,例如动态配置、服务发现、健康检查等。
可观察性
- 高级监控和追踪:Envoy 提供丰富的指标、日志和分布式追踪功能,能够与 Prometheus、Grafana、Jaeger 等工具无缝集成,使得服务之间的调用和性能问题能够被详细地监控和追踪。
- 丰富的可视化数据:支持详细的统计数据和可视化,帮助运维人员了解系统内部的工作情况。
动态配置和管理
- xDS API:Envoy 使用 xDS API 进行动态配置,允许管理者通过中心化的控制平面动态调整路由、限流、熔断等配置,而无需重新启动代理。这在频繁变化的微服务环境中尤为重要。
- 热重载配置:配置变更不需要重启服务,这一点在生产环境中尤其关键,能够保证服务的连续性。
丰富的功能
- 全面的 L7 代理功能:除了基本的 L4 负载均衡,Envoy 还提供 L7 代理功能,如 HTTP/2 和 gRPC 支持、流量劫持、路由控制、流量镜像等,适用于复杂的微服务通信需求。
- 服务发现和负载均衡:Envoy 支持多种服务发现机制和负载均衡策略,能够适应不同的微服务架构和部署环境。
扩展性和插件化
- 可扩展架构:Envoy 的架构设计允许开发者通过插件扩展其功能,使其能够适应特定的业务需求。
- WebAssembly(Wasm)支持:Envoy 支持通过 Wasm 插件进行扩展,提供了一种灵活、安全且高效的扩展机制。
社区和生态系统
- 活跃的社区:Envoy 由一个活跃且不断壮大的开源社区支持,Lyft、Google 等大型科技公司积极参与,确保了项目的持续发展和创新。
- 广泛的集成:Envoy 已被集成到许多开源项目和商业产品中,特别是在 Service Mesh 领域,如 Istio 和 Consul Connect,这些项目将 Envoy 作为数据平面代理,进一步扩大了其影响力和应用范围。
安全性
- 先进的安全特性:Envoy 提供全面的安全功能,包括 TLS 终结和起源验证、mTLS(双向 TLS)、RBAC(基于角色的访问控制)等,确保服务间通信的安全性。
对比 Nginx 和 HAProxy
虽然 Nginx 和 HAProxy 也在不断发展并引入了许多现代功能,但 Envoy 的设计初衷和功能集更贴合微服务架构的需求。具体对比:
- 动态配置:Envoy 的 xDS API 和热重载配置比 Nginx 和 HAProxy 的静态配置文件和较为复杂的动态配置管理更为先进。
- L7 代理功能:Envoy 的 L7 代理功能和对 HTTP/2、gRPC 的支持更为全面,而 Nginx 和 HAProxy 主要还是在 L4 和基础的 L7 代理功能上。
- 可观察性:Envoy 原生支持高级监控和分布式追踪,而 Nginx 和 HAProxy 需要依赖额外的插件或外部工具。
- 扩展性:Envoy 通过 Wasm 插件提供了高效的扩展机制,而 Nginx 和 HAProxy 在插件化和扩展性上较为有限。
综上所述,Envoy 的现代化设计、高度的可观察性、动态配置能力、丰富的功能集、强大的扩展性和活跃的社区,使得它在微服务架构中更具优势,从而在与 Nginx 和 HAProxy 的竞争中脱颖而出,成为 Service Mesh 体系的核心组件。