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

Envoy 内部结构

控制平面挂了到底什么会停

在 TT Lab 中继续学习

一句话总结

xDS 是代理从外部获取配置的通道。提供监听器的叫 LDS,提供集群的叫 CDS,只提供端点的叫 EDS。核心性质有两个——无需重启即可替换,以及错误的更新会被拒绝,并继续使用旧配置。

为什么需要它

到目前为止,所有配置都是写进文件再重新启动进程。只有几台服务器时还能忍受。但在 Kubernetes 中,Pod 一天要启动和消失几百次。如果每次端点列表变化都重启代理,重启期间的请求怎么办?又如何避免重启引发重启的局面?

于是方向被颠倒了过来:代理保持不动,只把配置推送进去。代理启动时先介绍“我是这样一个代理”(node),并订阅所需的资源。控制平面一直观察集群状态,把变化的部分发给该代理。这就是服务网格中数据平面与控制平面分离的地方,也是 Ingress 控制器所做工作的全部。

工作原理

根据提供的内容,名称有所不同。

名称 提供的内容 何时变化
LDS 监听器 端口或过滤器链变化时
CDS 集群 服务增加或减少时
EDS 仅端点 Pod 启动或消失时(最频繁)
RDS 路由表 路由规则变化时
SDS 证书 证书更新时

端点之所以单独成项,是因为它变化得最频繁。每启动一个 Pod 就重新发送整个集群定义,是一种浪费。

获取的方式有三种。打开 gRPC 流并保持的方式是实际的网格所使用的,也有用 REST 定期查询的方式,还有订阅文件的方式。最后一种用于实验和测试,协议的核心部分(订阅、更新、拒绝、版本)在三者中是相同的。

更新是原子性的,失败时会回退。这是 xDS 中最重要的性质。如果收到的配置不符合 schema,或者无法解析,代理会拒绝整个更新,并继续使用最后一次成功的配置。流量不会中断。所以“控制平面挂了,网格就挂了”这种说法并不准确——只是收不到新配置,而当前的配置仍然在正常运行。

作为代价,没有人会告诉你。所以需要监控的数字是固定的。

cluster_manager.cds.update_success     갱신이 도착해 반영된 횟수
cluster_manager.cds.update_rejected    도착했지만 거절된 횟수
listener_manager.lds.update_success    리스너 쪽 같은 숫자

update_success 停滞,说明配置没有送达;update_rejected 上升,说明配置送是送来了,但无法接受。这是完全不同的两个问题,需要修复的地方也不同。

确认是否送达的位置也是单独的。/config_dump 把静态资源和动态资源分开展示(static_clusters 和 dynamic_active_clusters)。要看“我发送的配置有没有送达”,就看动态一侧。

在现场相遇的样子

“改了配置,却没有生效。”分为两种情况。动态一侧的转储中没有,就是没有送达(订阅、连接问题);有,但行为不同,就是配置本身与意图不符。先把这两种情况区分开,查找范围就缩小了一半。

“重启了控制平面,什么都没有发生。”这是正常的。代理持有最后一次的配置继续运行。问题在于,如果这种状态持续很久,新启动的 Pod 就无法加入网格。“现在一切正常”与“很快就会出问题”这两个事实同时为真。

拒绝悄悄累积的情况。即使控制平面生成的配置出了问题,流量仍然流动,所以没有人知道。几周之后,它会以“只有这个服务走的是旧路由”的形式暴露出来。答案是给 update_rejected 设置告警。

官方文档:xDS REST and gRPC protocol · Bootstrap configuration · Administration interface

下一项实验要做什么

先确认静态配置即使修改了文件也不会改变,然后把同一个代理改为文件订阅方式。从集群资源中去掉一个端点,统计它无需重启就生效的情况,再无中断地替换监听器资源,最后故意发送一份损坏的配置,亲眼看它被拒绝而流量仍然继续流动。并确认这件事会记录在哪个数字上。

本实验环境中没有真正的 gRPC 控制平面,所以用文件订阅代替。发送内容的形态和代理的处理方式是相同的,但连接断开时重新订阅这类传输层的行为,在这里看不到。