TT Lab
开始
学习 学习路径 课程

Envoy 内部结构

放入一个坏的上游再观察集群

在 TT Lab 中继续学习

目标

分别建立获知端点的方式和判断是否健康的方式,并亲手构建健康端点不足时 Envoy 会选择的两条路径。

为什么重要

运维代理时,实际上最常看的不是路由表,而是集群列表——哪里有几台服务器,其中几台是健康的。能读懂这些数字,503 报告就有一半当场能处理完。尤其是 panic 模式,如果不亲眼见过一次,在生产环境中第一次遇到时,就会卡在“都死光了,为什么还一直在发”。优先级接管也是如此,只读配置,无法体会下面一层什么时候开始接收流量。

步骤

  1. 启动四个上游——8084、8086 为 ok,8085、8087 为 fail。在 /root/envd-cluster/cluster.yaml 中放置 STATIC 集群 pool(端点为 8084、8085、8086)和 /pool 路由并启动(管理端口 9941,监听器 127.0.0.1:10041)。从 /clusters 中只挑出以 pool:: 开头的行,保存到 /root/envd-cluster/01-pool.txt。
  2. 添加 STRICT_DNS 集群 bydns——地址为 localhost,端口为 8084,dns_lookup_family 为 V4_ONLY。同时放置 /bydns 路由。从 /config_dump?resource=static_clusters 中为每个集群提取一行 이름 타입(占位符依次为名称与类型),保存到 /root/envd-cluster/02-types.txt。
  3. 为 pool 添加主动健康检查——interval 为 1 秒,timeout 为 1 秒,两个阈值都为 1,http_health_check 的路径为 /healthz。稍等片刻后,从 /clusters 中只挑出 pool 端点的 health_flags 行,保存到 /root/envd-cluster/03-health.txt。
  4. 向 /pool 请求 12 次,统计各上游收到了多少次,以 p8084=、p8085=、p8086=、total= 四行写入 /root/envd-cluster/04-spread.txt(值为收到的次数)。
  5. 添加集群 panic——端点 8085、8087 都是 fail,并设置同样的主动健康检查。同时放置 /panic 路由。请求 6 次后,在 /root/envd-cluster/05-panic.txt 中写入 codes=(收到的 HTTP 状态码,用空格分隔)、lb_healthy_panic=(同名统计的值)、membership_healthy= 三行。
  6. 添加集群 tiered——在 priority: 0 放置 8085(fail),在 priority: 1 放置 8086(ok),并设置同样的主动健康检查。同时放置 /tiered 路由并请求 6 次,在 /root/envd-cluster/06-priority.txt 中写入 served_by=(响应的端口)、count=(该端口收到的次数)两行。
  7. 在 /root/envd-cluster/07-inventory.txt 中,为每个集群写一行 이름 타입 엔드포인트수 성한수(占位符依次为名称、类型、端点数、健康端点数),四个值用空格隔开(按名称排序)。值不要用眼睛数,要从 /config_dump 和 /stats 中提取。
  8. 在 /root/envd-cluster/08-report.md 中写入 healthy=(pool 的健康端点数)、total=(pool 的全部端点数)、panic_requests_sent=(panic 模式下发出了请求则为 yes)、failover_port=(第 6 步实际响应的端口)四行,并在下面至少写四行学到的内容。

参考

给一个名称挂上三个地址

启动四个上游——8084、8086 为 ok,8085、8087 为 fail。在 /root/envd-cluster/cluster.yaml 中放置 STATIC 集群 pool(端点为 8084、8085、8086)和 /pool 路由并启动(管理端口 9941,监听器 127.0.0.1:10041)。从 /clusters 中只挑出以 pool:: 开头的行,保存到 /root/envd-cluster/01-pool.txt。

集群是“可以用这个名称来调用的服务器”的集合。STATIC 是把地址原样写进配置的最简单方式,因此不修改配置,列表就不会变化。上游用 python3 /opt/lab/envoy/upstream.py <포트> ok|fail(占位符为端口)启动——fail 无论查询哪个路径都会返回 503。/clusters 会为每个端点输出多行,请用 grep 过滤后保存。

不写地址,改写名称

添加 STRICT_DNS 集群 bydns——地址为 localhost,端口为 8084,dns_lookup_family 为 V4_ONLY。同时放置 /bydns 路由。从 /config_dump?resource=static_clusters 中为每个集群提取一行 이름 타입(占位符依次为名称与类型),保存到 /root/envd-cluster/02-types.txt。

获知端点的方式就是集群的 type。STATIC 使用配置中写的地址,STRICT_DNS 定期重新解析名称,把响应中包含的地址全部作为端点,LOGICAL_DNS 则只抓住其中一个继续使用。EDS 是由控制平面推送列表的方式。用 jq -r '.configs[]?.cluster | "\(.name) \(.type)"' 可以提取这两个值。

与请求分开,定期探测

为 pool 添加主动健康检查——interval 为 1 秒,timeout 为 1 秒,两个阈值都为 1,http_health_check 的路径为 /healthz。稍等片刻后,从 /clusters 中只挑出 pool 端点的 health_flags 行,保存到 /root/envd-cluster/03-health.txt。

异常点检测(outlier detection)是根据实际请求的失败情况来剔除端点,而主动健康检查则与请求无关,单独进行探测。所以即使没有流量的时段也能知道状态,第一个请求也不会发往故障的服务器。代价是每台服务器会多出一份周期性负载。/clusters 的 health_flags 在健康时为 healthy,主动检查失败时为 /failed_active_hc。由于检查周期为 1 秒,配置启用之后马上可能还没有判定结果——请等到出现标记为止。

不会向不健康的地方发送

向 /pool 请求 12 次,统计各上游收到了多少次,以 p8084=、p8085=、p8086=、total= 四行写入 /root/envd-cluster/04-spread.txt(值为收到的次数)。

负载均衡只在健康的端点之间进行。所以,没有通过主动检查的那一个,一次请求都不应该收到。响应正文中包含端口,据此统计即可。如果用 --concurrency 1 启动,两个健康的端点应该正好各分到一半。

一个健康的都没有时怎么办

添加集群 panic——端点 8085、8087 都是 fail,并设置同样的主动健康检查。同时放置 /panic 路由。请求 6 次后,在 /root/envd-cluster/05-panic.txt 中写入 codes=(收到的 HTTP 状态码,用空格分隔)、lb_healthy_panic=(同名统计的值)、membership_healthy= 三行。

当健康比例降到阈值(默认 50%)以下时,Envoy 会忽略健康信息,把请求发给所有端点。这称为 panic 模式。看上去奇怪,但判断很简单——检查方也有可能出错,如果哪里都不发,就一定是故障;如果发,至少还有一部分能活下来。是否发生过,通过 cluster.<이름>.lb_healthy_panic(占位符为集群名称)统计来看。用 curl -s localhost:<admin>/stats | grep ... 只取出值。

上面全部失效,就转到下面

添加集群 tiered——在 priority: 0 放置 8085(fail),在 priority: 1 放置 8086(ok),并设置同样的主动健康检查。同时放置 /tiered 路由并请求 6 次,在 /root/envd-cluster/06-priority.txt 中写入 served_by=(响应的端口)、count=(该端口收到的次数)两行。

可以为每个端点分组设置 priority。平时只使用优先级 0。优先级 0 的健康比例下降多少,就由优先级 1 承接多少,优先级 0 全部失效时,一切都转到优先级 1。让其他区域的备用服务器平时闲置、只在故障时使用,就是这样构成的。/clusters 输出中,每个端点都有一行 priority,可以据此确认处于哪个层级。

制作四个集群的清单

在 /root/envd-cluster/07-inventory.txt 中,为每个集群写一行 이름 타입 엔드포인트수 성한수(占位符依次为名称、类型、端点数、健康端点数),四个值用空格隔开(按名称排序)。值不要用眼睛数,要从 /config_dump 和 /stats 中提取。

生产环境中最先看的表就是这个——哪个集群有几台服务器,其中几台是健康的。cluster.<이름>.membership_total(占位符为集群名称)和 membership_healthy 这两个统计就是这两个数字。类型可以从 /config_dump?resource=static_clusters 得到。把从两处提取的值按集群名称拼接起来即可。

留下集群运维备忘

在 /root/envd-cluster/08-report.md 中写入 healthy=(pool 的健康端点数)、total=(pool 的全部端点数)、panic_requests_sent=(panic 模式下发出了请求则为 yes)、failover_port=(第 6 步实际响应的端口)四行,并在下面至少写四行学到的内容。

值请取自前面步骤创建的文件——凭记忆填写会出现偏差。说明行中要写下像“主动健康检查与异常点检测的区别”这样下次设计时用得上的句子。