前面几篇按请求路径走到了 Cluster、连接池与 outlier。动态配置场景下,这些对象不是一份 YAML 一次性出现,而是控制面通过 xDS 按类型推送的资源,彼此用名字引用。推送顺序错了,就会出现「控制面已更新、数据面短暂黑洞或仍走旧路由」。本文只钉资源树、命名依赖与顺序;流协议上的 SotW / Incremental / ADS 细节见 第 10 篇。
本文是「Envoy / 数据面代理内核」系列第 9 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 8 篇 · 连接池 / outlier 上游资源限额 第 9 篇 · xDS 资源树 依赖、命名、顺序 第 10 篇 · ADS / SotW / Delta 流与 ACK 上一篇:连接池、熔断与 outlier · 下一篇:ADS / SotW / Incremental
版本锚定:Envoy v1.39.0 xDS configuration API overview、xDS REST and gRPC protocol(Resource warming、Eventual consistency)。
本篇不展开:DiscoveryRequest 的 nonce / version 状态机、SotW 与 Delta 报文差(第 10 篇)、证书轮转与 Listener 热更新边界(第 11 篇)。只回答「资源树长什么样、名字如何引用、推送顺序为何重要」。
一、四类核心资源(外加 SDS)
官方协议文档对典型 HTTP 代理给出的核心类型:
| 简称 | 资源类型 | 角色 |
|---|---|---|
| LDS | Listener |
监听与 filter chain;可内嵌或引用 RDS |
| RDS | RouteConfiguration |
虚拟主机与路由;引用 cluster 名 |
| CDS | Cluster |
上游逻辑组;可引用 EDS |
| EDS | ClusterLoadAssignment |
具体 endpoint、locality、priority、metadata |
| SDS | Secret | 证书与校验材料(Listener/Cluster 传输层) |
此外还有 VHDS、SRDS、RTDS、ECDS 等,用于巨量子域、runtime、扩展配置拆分——本篇不展开,只记住它们仍挂在同一棵「按名引用」的树上。
flowchart TD
LDS["LDS Listener"] -->|"rds name"| RDS["RDS RouteConfiguration"]
RDS -->|"cluster name"| CDS["CDS Cluster"]
CDS -->|"eds service_name"| EDS["EDS ClusterLoadAssignment"]
LDS -.->|"optional"| SDS["SDS Secret"]
CDS -.->|"optional"| SDS
Envoy 启动时拉取 Listener 与 Cluster 根;再按引用拉取所需的 RouteConfiguration 与 ClusterLoadAssignment。协议原文:每个 Listener 或 Cluster 都是配置树的一个根。
SDS 不改变 LDS→EDS 的逻辑边,但常成为 warming 阻塞点:Listener 或 Cluster 的 TLS socket 引用了尚未下发的 secret 时,表现是「证书相关资源未就绪」,而不是路由表错误。证书轮转与 Listener 热更新边界见第 11 篇;本篇只需把 SDS 画进树上,避免排障时只查 RDS。
二、命名即契约
依赖边是字符串名字,不是外键级联删除:
- Listener 经 HCM 的 RDS
ConfigSource+ route config name 订阅某条RouteConfiguration。 - Route 的
cluster/ weighted clusters 填写 Cluster 名;该名必须能在 CDS(或静态 cluster)中解析。 - Cluster 的 EDS 配置用
service_name(或默认 cluster 名)订阅ClusterLoadAssignment。 - SDS secret 名挂在 TLS transport socket / SDS config 上。
后果:
- RDS 先指向新 cluster
Y,而 CDS/EDS 尚无Y→ 请求no_cluster或 warming 未完成导致监听未上线(见下节)。 - CDS 更新 cluster 定义会 排空旧连接池并重建;仅 EDS 增删主机则不影响既有主机上的池(官方 CDS 概述建议 CDS 集群仍走 EDS)。
- SotW 下非 LDS/CDS 类型的「删除」常靠父资源不再引用间接发生;空响应语义因类型而异——细节留待第 10 篇,本篇只需避免「以为发了空 EDS 就清空」的假设而不查协议。
Bootstrap 里通常静态给出「如何联系管理服务器」的
cluster;官方还提醒:依赖 xDS 的 cluster(例如 SDS 所用)在
static_resources
中应写在被依赖者之前,否则初始化变慢。
ConfigSource
决定某一类型资源从哪条管理通道来:独立 gRPC 上流、ADS
聚合流、或文件监视。Listener 内嵌的 RDS
ConfigSource、Cluster 内嵌的 EDS
ConfigSource 可以与 bootstrap
根配置不同——因此「CDS 已 ACK」完全不蕴含「该 cluster 的 EDS
也来自同一服务器或同一版本」。命名对齐之外,还要对齐订阅通道。
三、Warming:ACK 之前还有「能用」
Resource warming(v1.39.0 协议文档):
- Cluster warming
完成的条件:管理服务器提供了对应的
ClusterLoadAssignment(即使 endpoints 相对缓存无变化,Envoy 实现仍期望一次新的 EDS 响应;超时后可使用缓存 assignment)。 - Listener warming:若引用
RDS,需有可用的
RouteConfiguration。Envoy 实现上,若管理服务器不重发未变更的 RDS,可用上次 RouteConfiguration 完成 Listener warming;从未发送过则必须补发。
因此:
- 控制面日志里的「已推送」≠ Worker 上该 Listener 已开始接流量。
- 客户端对某次
DiscoveryResponse的 ACK 表示「孤立看来这些资源合法、意图应用」(协议原文),不等于依赖树已全部 warming 完毕、流量已切到新路由。第 1 篇坐标系里的「xDS 一致性轴」在此落地。
对「请求了但不存在的 RDS/EDS」,客户端用超时(文档建议约 15s)视为不存在,同时必须准备资源稍后出现时再推送。
四、为何顺序重要:make before break
xDS 是最终一致的。官方例子:仅知 cluster
X 时,RDS 从 X 改指
Y,而 CDS/EDS 尚未引入 Y,则会
blackhole 直至 Y 可知。
推荐的 make-before-break 顺序(协议 Eventual consistency considerations):
- 先推 CDS(若有新集群)。
- 再推对应 EDS。
- 再推 LDS(新 Listener 依赖的上游已在)。
- 再推与这些 Listener 相关的 RDS。
- 如有 VHDS,在相关 RDS 之后。
- 最后再删不再被引用的旧 CDS/EDS。
反向「先改 RDS 再补集群」是联调事故的高频原因。ADS 把多类型复用到单流,便于控制面显式排序;分类型多流则只有最终一致,更依赖控制面纪律——第 10 篇比较 SotW / Incremental / ADS。
sequenceDiagram
participant CP as ControlPlane
participant E as Envoy
CP->>E: CDS add cluster Y
CP->>E: EDS endpoints for Y
CP->>E: LDS listeners if needed
CP->>E: RDS repoint X to Y
CP->>E: CDS/EDS remove unused X
五、与数据面章节的接合
| 数据面对象 | 主要由谁下发 | 失败时像什么 |
|---|---|---|
| Filter chain / HCM | LDS(+ ECDS 等) | 监听不到或链选错 |
| 路由表 | RDS / VHDS / SRDS | 404 / 旧路由 |
| Cluster 策略与熔断 | CDS | 有名无实体、池重建抖动 |
| Endpoint / subset metadata | EDS | 无上游、空子集、priority 渗漏 |
| 证书 | SDS | 握手失败;warming 卡住 |
第 8 篇 的 503 在「树已就绪但限额打满」时出现;本篇的黑洞在「树边断裂或顺序错误」时出现。排障必须先问:是依赖没齐,还是齐了但池/熔断/outlier 拒绝?
静态配置与「仅 EDS 动态」仍是合法部署:官方 xDS configuration API overview 允许从全静态逐步加 EDS→CDS→RDS→LDS。每多一层动态,就多一条 warming 边与一种顺序约束——不要在只加了 RDS 的环境里假设 Listener 热更新行为与「全 xDS」相同。
六、谱系、争论与开放问题
谱系:Envoy 将「万能数据面」配置拆成可独立演进的资源类型(LDS/RDS/CDS/EDS/SDS),用 gRPC/REST 订阅替代整文件 reload。这与静态代理的「一份配置 → fork/reload」分叉;代价是最终一致与 warming 状态机。
争论:SotW(实现简单、LDS/CDS 每次全量)vs Incremental(带宽友好、可惰性加载)。大规模 EDS 抖动下,全量 SotW 的控制面与客户端 CPU 压力是开放工程问题——第 10–11 篇展开,本篇只把「树」钉死。
开放问题:跨资源事务(「RDS 与 CDS 原子切换」)并非协议一等公民;能否在不牺牲通用性的前提下做更强一致,仍属控制面产品设计空间。
七、参考资料
规范 / 官方文档(A)
- Envoy v1.39.0,xDS configuration API overview(EDS/CDS/RDS/LDS/SDS 分层叙述)。
- Envoy v1.39.0,xDS REST and gRPC protocol(资源类型、warming、make-before-break、ACK 语义)。
源码(A)
envoyproxy/envoytag v1.39.0:source/common/config/、source/server/config_validation/(订阅与 warming 路径后续篇细化)。
站内
- 第 8 篇 · 第 10 篇 · 第 1 篇全景 · 系列目录
- network/57 Envoy 架构剖析(名词地图,不替代本篇依赖顺序)
实验台账
- 本篇不粘贴
config_dump;有环境后再在第 11 / 15 篇写实跑片段。
八、小结
- LDS→RDS→CDS→EDS(+SDS) 靠资源名引用;Envoy 先拿 Listener/Cluster 根再拉子资源。
- Warming 决定 Listener/Cluster 何时可服务;ACK ≠ 依赖就绪。
- Make-before-break:先 CDS/EDS,再 LDS,再 RDS,最后删旧资源,避免黑洞。
- 流上如何 ACK/NACK、SotW 与 Delta 差在哪——见下一篇。
→ 系列目录 · 上一篇:连接池、熔断与 outlier · 下一篇:ADS / SotW / Incremental
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Envoy 数据面】Warming、SDS 与热更新:ACK 为何不等于新路由上量
拆解 Listener/Cluster warming、SDS 证书轮转与 xDS 热更新边界;说明为何协议 ACK 之后流量仍可能走旧路由或 503,并区分 xDS 热更新与 Hot restart。
【Envoy 数据面】生产排障:五条坐标系上的失败清单
按第 1 篇五条坐标系拆解无上游、路由未生效、证书/SDS、warming 黑洞、hot restart 与连接泄漏;给出 admin 核对顺序与观测信号入口,不虚构延迟数字。
【Envoy 数据面】Main / Worker 与配置快照:事件循环、TLS 与几乎无锁热路径
钉住 Envoy 单进程多线程模型:Main 管 xDS/Admin,Worker 绑连接终生;Event::Dispatcher 与 Thread Local Storage 如何把配置变成每线程可读快照,以及快照解决什么、解决不了什么。
【Envoy 数据面】数据面全景:从 Listener 到 xDS 的可编程代理内核
定位 Envoy 相对 Nginx/HAProxy 静态配置代理与 Mesh 选型叙事的生态位;钉住请求路径、配置快照、FilterChainMatch、xDS warming、上游资源五条坐标系,并给出与 network/57 的分工及 16 篇阅读路线。