Envoy 是怎么从控制平面拿配置的?LDS、RDS、CDS、EDS 各是什么、什么顺序?ACK 和 NACK 是什么?更新推到流量切换要多久?控制平面挂了数据平面会怎样?这篇用自己写的最小 ADS 服务和真实的 Envoy 逐项观察。
t(s) | 方向 | 类型 | version_info | 资源名 | nonce -----+-----+-----+--------------+-----+--------- 0.06 | 流打开 | | | | 0.07 | 请求 | CDS | (空) | (空) | (空) 0.07 | 发出 | CDS | 1 | c_a | 2e481018 0.07 | 请求 | EDS | (空) | c_a | (空) 0.07 | 发出 | EDS | 1 | c_a | b405840b 0.07 | 请求 | CDS | 1 | (空) | 2e481018 0.07 | 请求 | LDS | (空) | (空) | (空) 0.07 | 发出 | LDS | 1 | l0 | 98c4f889 0.07 | 请求 | EDS | 1 | c_a | b405840b 0.07 | 请求 | RDS | (空) | r0 | (空) 0.07 | 发出 | RDS | 1 | r0 | 7f7e155d 0.07 | 请求 | LDS | 1 | (空) | 98c4f889 0.07 | 请求 | RDS | 1 | r0 | 7f7e155d Envoy 起来到第一个请求能成功用了 0.08 s。表里各资源类型第一次被请求的先后是 CDS、EDS、LDS、RDS:最先是 CDS(不带资源名,订阅全部集群);收到 CDS 之后请求其中集群的 EDS(带上集群名 c_a);再请求 LDS(订阅全部监听器);收到 LDS 之后请求监听器引用的 RDS(带上路由配置名 r0)。先集群、后监听器、最后路由,避免监听器已经开始接流量而它引用的集群还没准备好(这个顺序的理由是我对 xDS 文档的了解,表里的先后是实测)。每个资源类型收到之后 Envoy 回一条带着刚收到的 version_info 和 nonce 的请求,就是 ACK
Envoy 按 CDS、EDS、LDS、RDS 的顺序订阅,每收到一类资源回一条带 version_info 和 nonce 的请求作为 ACK。
t(s) | 方向 | version_info | 内容 / error_detail
-----+------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0.10 | 发出 | 2 | l0
0.10 | NACK | 1 | Error adding/updating listener(s) l0: Error: terminal filter named envoy.filters.http.nonexistent of type envoy.filters.http.router must be the last filter in a http filter chain.
1.61 | 发出 | 3 | l0
1.61 | 请求 | 3 | (空)
推送坏配置期间(NACK 之后)通过 Envoy 的 10 个请求:Counter({'A': 10});推送有效更新之后的 5 个请求:Counter({'A': 5})。坏配置被 NACK(error_detail 里写着原因),version_info 仍然是上一个被接受的版本,Envoy 继续用旧监听器,流量不受影响;控制平面推了有效版本之后 Envoy 回 ACK(version_info 变成新版本)不接受的配置被 NACK,version_info 保持上一个被接受的版本,数据平面继续用旧配置。
更新类型 | 到流量切换 中位数(ms) | 最小(ms) | 最大(ms)
---------------+---------------+--------+-------
(a)EDS 更新 | 1.4 | 1.0 | 9.9
(b)RDS 更新(换路由) | 0.7 | 0.6 | 4.7
(c)新集群没有端点:路由改到 c_c 之后的前 1 s(EDS 还没推)里的请求结果 {'HTTP 503': 67};EDS 在第 1007 ms 推出,第一次收到 B 的响应在 1014 ms。路由指向了一个还没有端点的集群,在端点到位之前请求得不到成功的响应同一台机器上的推送到切换是毫秒级;路由指向还没有端点的新集群会出现 503 窗口。
控制平面停了 6 s 期间的 102 个请求:Counter({'B': 102})(流量不受控制平面断开的影响,Envoy 继续用最后一份配置);控制平面重启之后 Envoy 重新建立 ADS 流用了 11.6 s
重新连上之后 Envoy 重新发来的请求:[('CDS', '3', '(空)'), ('EDS', '33', 'c_c,c_b,c_a'), ('LDS', '3', '(空)'), ('RDS', '32', 'r0'), ('CDS', '3', '(空)'), ('EDS', '33', 'c_c,c_b,c_a'), ('LDS', '3', '(空)'), ('RDS', '32', 'r0')];重连后推送更新(c_a 的端点换成 B)之后的 5 个请求:Counter({'B': 5})
数据平面与控制平面解耦:控制平面不可用时已经下发的配置照常工作,只是无法更新;Envoy 在控制平面恢复之后 11.6 s 重新连上(更长时间的断开下重连间隔会不会变长,我没有测),重连后重新订阅并拿到当前版本
ERRORS {}已下发的配置照常工作,只是不能更新;控制平面恢复后 Envoy 重新连上并重新订阅。