Envoy 上游集群健康检查
Upstreams 健康状态检测
- 健康状态检测用于确保代理服务器不会将下游客户端的请求代理至工作异常的上游主机;
-
Envoy支持两种类型的健康状态检测,二者均基于集群进行定义;
健康状态检测类型
主动检测
主动检测(Active Health Checking):Envoy周期性地发送探测报文至上游主机,并根据其响应判断其健康状态;Envoy目前支持三种类型的主动检测:
-
HTTP:在 HTTP 健康检查期间,Envoy 将向上游主机发送 HTTP 请求。默认情况下,如果主机健康,它会收到 200 响应。预期和可重试的响应代码是可 配置的。如果上游主机想立即通知下游主机不再向其转发流量,则上游主机可以返回非预期或不可重试的状态码(默认为任何非 200 码)。
-
L3/L4:在 L3/L4 健康检查期间,Envoy 将向上游主机发送一个可配置的字节缓冲区。如果主机被认为是健康的,它期望字节缓冲区在响应中得到回显。Envoy 还支持仅连接 L3/L4 健康检查。
- redis:Envoy 将发送 Redis PING 命令并期待 PONG 响应。上游 Redis 服务器可以使用 PONG 以外的任何内容进行响应,从而立即导致主动健康检查失败。或者,Envoy 可以对用户指定的密钥执行 EXISTS。如果密钥不存在,则视为通过了健康检查。这允许用户通过将指定的键设置为任何值并等待流量耗尽来标记 Redis 实例以进行维护。
被动检测
被动检测(Passive Health Checking):Envoy通过异常检测(Outlier Detection)机制进行被动模式的健康状态检测;
-
目前,仅http router、tcp proxy和redis proxy三个过滤器支持异常值检测;
-
Envoy支持以下类型的异常检测
-
连续5XX:意指所有类型的错误,非http router过滤器生成的错误也会在内部映射为5xx错误代码;
-
连续网关故障:连续5XX的子集,单纯用于http的502、503或504错误,即网关故障;
-
连续的本地原因故障:Envoy无法连接到上游主机或与上游主机的通信被反复中断;
-
成功率:主机的聚合成功率数据阈值;
-
健康检查事件记录
- 通过在HealthCheck 配置中指定日志文件路径,Envoy 可以选择生成每个健康检查器的弹出和添加事件日志。日志结构为 HealthCheckEvent 消息的 JSON 类型。
- 通过将always_log_health_check_failures 标志设置为 true,可以将 Envoy 配置为记录所有健康检查失败事件。
Upstreams主动健康状态检测配置格式
clusters:
- name: ...
...
load_assignment:
endpoints:
- lb_endpoints:
- endpoint:
health_check_config:
port_value: 8080 # 自定义健康状态检测时使用的端口;
address:
socket_address:
address: localhost
port_value: 80
health_checks:
- timeout: {...} # 超时时长
interval: {...} # 时间间隔
initial_jitter: {...} # 初始检测时间点散开量,以毫秒为单位;
interval_jitter: {...} # 间隔检测时间点散开量,以毫秒为单位;
interval_jitter_percent: ... # 间隔检测百分比,interval_ms * interval_jitter_percent / 100
unhealthy_threshold: {...} # 将主机标记为不健康状态的检测阈值,即至少多少次不健康的检测后才将其标记为不可用;
healthy_threshold: {...} # 将主机标记为健康状态的检测阈值,但初始检测成功一次即视主机为健康;
reuse_connection: {...} # 在健康检查之间重用健康检查连接。默认为true。
http_health_check: {...} # HTTP类型的检测;包括此种类型在内的以下四种检测类型必须设置一种;
tcp_health_check: {...} # TCP类型的检测;
grpc_health_check: {...} # GRPC专用的检测;
custom_health_check: {...} # 自定义检测;
no_traffic_interval: {...} # 定义未曾调度任何流量至集群时其端点健康检测时间间隔,一旦其接收流量即转为正常的时间间隔;
no_traffic_healthy_interval: {...} # “无流量健康间隔”是一个特殊的健康检查间隔,用于集群没有收到流量时当前正在通过主动健康检查的主机(包括新主机)。
unhealthy_interval: {...} # 标记为“unhealthy”状态的端点的健康检测时间间隔,一旦重新标记为“healthy”即转为正常时间间隔;
unhealthy_edge_interval: {...} # 端点刚被标记为“unhealthy”状态时的健康检测时间间隔,随后即转为同unhealthy_interval的定义;
healthy_edge_interval: {...} # 端点刚被标记为“healthy”状态时的健康检测时间间隔,随后即转为同interval的定义;
event_log_path: ... # 指定健康检查事件日志的路径。如果为空,则不会写入事件日志。
always_log_health_check_failures: ... # 如果设置为 true,则将始终记录运行状况检查失败事件。如果设置为 false,则仅记录初始运行状况检查失败事件。默认值为false。
tls_options: {...} # tls相关的配置
transport_socket_match_criteria: {...} # 可选的键/值对,用于匹配集群传输套接字匹配项中指定的传输 套接字。
主动健康状态检查配置示例
TCP类型
TCP类型配置参数
clusters:
- ...
...
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
tcp_health_check:
send: {...} # 空负载意味着仅连接的健康检查。
receive: [] # 检查响应时,执行“模糊”匹配,以便必须找到每个有效负载块,并且按照指定的顺序,但不一定是连续的。
TCP类型配置格式
clusters:
- name: local_service
connect_timeout: 0.25s
lb_policy: ROUND_ROBIN
type: EDS
eds_cluster_config:
eds_config:
api_config_source:
api_type: GRPC
grpc_services:
- envoy_grpc:
cluster_name: xds_cluster
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
tcp_health_check: {}
TCP类型配置示例
查看代码
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
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
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: web_cluster_01 }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: myservice, port_value: 80 }
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
tcp_health_check: {}
HTTP类型
HTTP类型配置说明
- http类型的检测可以自定义使用的path、host和期望的响应码等,并能够在必要时修改(添加/删除)请求报文的标头
HTTP类型配置参数
health_checks: []
- ...
http_health_check:
"host": "..." # 检测时使用的主机标头,默认为空,此时使用集群名称;
"path": "..." # 检测时使用的路径,例如/healthz;必选参数;
"service_name_matcher": "..." # 用于验证检测目标集群服务名称的参数,可选;
"request_headers_to_add": [] # 向检测报文添加的自定义标头列表;
"request_headers_to_remove": [] # 从检测报文中移除的标头列表;
"expected_statuses": [] # 期望的响应码列表;
"receive": [] # 指定一个 HTTP 预期响应列表,以匹配response_buffer_size响应正文的第一个字节。如果已设置,则预期响应检查和状态代码都将确定运行状况检查。检查响应时,会执行“模糊”匹配,以便必须找到每个有效负载块,并且按照指定的顺序,但不一定是连续的。
"response_buffer_size": {...} # 指定用于有效负载匹配的响应缓冲区的大小(以字节为单位)。默认值为 1024。设置为 0 意味着 Payload 将与整个响应匹配。
"retriable_statuses": [] # 指定被认为可重试的 HTTP 响应状态列表。如果提供,此范围内的响应将计入配置的unhealthy_threshold,但不会导致主机立即被视为不健康。每个范围的开始和结束都是必需的。 expected_statuses 字段优先,即如果状态代码 200 既可重试又可预期,则 200 响应将被视为成功的健康检查。默认情况下,所有响应都不在 expected_statuses将导致主机立即被视为不健康,即如果预期状态代码 200 并且没有配置可重试状态,则任何非 200 响应将导致主机被标记为不健康。
"codec_client_type": ... # 使用指定的应用程序协议进行健康检查。
"method": ... # 于健康检查的 HTTP 方法,默认为“GET”。支持 GET、HEAD、POST、PUT、DELETE、OPTIONS、TRACE、PATCH 方法,但不支持制作请求正文。不允许使用 CONNECT 方法,因为它不适用于运行状况检查请求。如果该方法期望得到非 200 响应,则需要在expected_statuses中进行设置。
HTTP类型配置格式
clusters:
- name: local_service
connect_timeout: 0.25s
lb_policy: ROUND_ROBIN
type: EDS
eds_cluster_config:
eds_config:
api_config_source:
api_type: GRPC
grpc_services:
- envoy_grpc:
cluster_name: xds_cluster
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
http_health_check:
host: ... # 默认为空值,并自动使用集群为其值;
path: ... # 检测针对的路径,例如/healthz;
expected_statuses: # 期望的响应码,默认为200;
start: ... # 范围的开始(包括)
end: ... # 范围的结尾(不包括)
HTTP类型配置示例
查看代码
admin:
profile_path: /tmp/envoy.prof
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
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
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: webservice
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: web_cluster_01 }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: web_cluster_01
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: web_cluster_01
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: myservice, port_value: 80 }
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 2
healthy_threshold: 2
http_health_check:
path: /livez
expected_statuses:
start: 200
end: 399
参考文档
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/health_checking
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/health_check.proto#config-core-v3-healthcheck
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/health_check.proto#envoy-v3-api-msg-config-core-v3-healthcheck-tcphealthcheck
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/health_check.proto#envoy-v3-api-msg-config-core-v3-healthcheck-httphealthcheck