土法炼钢兴趣小组的算法知识备份

【Envoy 数据面】ADS / SotW / Incremental:流、ACK/NACK 与 version/nonce

文章导航

分类入口
networkproxy
标签入口
#envoy#xds#ads#sotw#incremental#delta#ack#nack#nonce

目录

第 9 篇 把 LDS→RDS→CDS→EDS 依赖树钉住了。联调时第二个坑通常不是「缺哪种资源」,而是:同一套依赖,走分类型 gRPC 流还是 ADS;走 State-of-the-World 还是 Incremental;ACK 了为什么路由还是旧的。

本文只回答协议层三件事:四种传输变体差在哪;version_info / nonce / ACK/NACK 各自承诺什么;NACK 之后控制面与数据面分别会怎样。Warming 与「ACK 之后流量何时切」留给 第 11 篇

本文是「Envoy / 数据面代理内核」系列第 10 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 9 篇 · xDS 资源树 LDS→RDS→CDS→EDS 依赖
第 10 篇 · ADS / SotW / Delta 流变体、ACK/NACK、version/nonce
第 11 篇 · Warming / SDS ACK≠流量;证书与热更新边界

版本锚定:Envoy v1.39.0 xDS REST and gRPC protocol;API v3。无本机联调输出,不伪造 ACK 时序或 config_dump


一、四个变体:两个正交维度

官方协议把 streaming gRPC xDS 拆成两个独立维度(v1.39.0 xDS protocol):

  1. SotW vs Incremental(Delta):推送经济学——整表还是差量。
  2. 分类型流 vs ADS:一致性经济学——多流最终一致,还是单流可排序。

交叉得到四种变体:

变体 SotW / Delta 典型 RPC
Basic xDS SotW 每资源类型一条流 StreamListeners
Incremental xDS Delta 每资源类型一条流 DeltaListeners
ADS SotW 单流多路复用 StreamAggregatedResources
Incremental ADS Delta 单流多路复用 DeltaAggregatedResources
flowchart LR
  subgraph dims ["Two dimensions"]
    SotW["SotW full snapshot"]
    Delta["Incremental deltas"]
    PerType["Per-type streams"]
    ADS["Single ADS stream"]
  end
  SotW --> Basic["Basic xDS"]
  SotW --> ADSSotW["ADS SotW"]
  Delta --> Inc["Incremental xDS"]
  Delta --> ADSDelta["Incremental ADS"]
  PerType --> Basic
  PerType --> Inc
  ADS --> ADSSotW
  ADS --> ADSDelta

SotW:客户端每次请求带齐感兴趣的 resource_names;对 LDS/CDS,服务端在每次响应里返回当前订阅集合的全集。缺席的名字被视为删除。订阅从 99 扩到 100 时,客户端要重发 100 个名字,服务端往往也要再推 100 份资源——大规模 EDS 下这是带宽与抖动税。

Incremental:请求用 resource_names_subscribe / resource_names_unsubscribe;响应只含增删改。nonce 必填,用来把 DeltaDiscoveryResponse 与后续 ACK/NACK 配对。system_version_info 仅调试用,不承担 SotW 那套「资源类型实例版本」角色。

ADS:所有 type URL 复用一条 gRPC 双向流;每个 type URL 仍是独立的 DiscoveryRequest/Response 子序列,nonce 按 type URL 分别跟踪。官方动机很明确:分布式多管理端很难保证 make-before-break;ADS 让同一控制面按 CDS→EDS→LDS→RDS 顺序推送,降低短暂黑洞概率。

选型句:要可排序推送选 ADS;要大规模差量选 Incremental;两者可叠加为 Incremental ADS。 分类型 SotW 适合规模可控、可容忍最终一致窗口的部署。


二、version 与 nonce:两套不同的时钟

2.1 version_info(资源类型实例版本)

每个 xDS 资源类型有一个版本字符串;该类型下任一资源变更,版本跟着变。SotW 响应的 version_info 表示服务端声称的当前版本;客户端在后续请求里回填自己已接受的最近有效版本

要点:

2.2 nonce

每个 DiscoveryResponsenonce;客户端后续请求必须把 response_nonce 设为该流上最近一次收到的 nonce。nonce 不跨流重启存活;ADS 上按 type URL 分开记。

nonce 解决的是 SotW 特有竞态:客户端可能在版本 X 上追加 resource_names hint,而服务端同时推出版本 Y。若只看 version_info,hint 请求容易被误判成对 Y 的拒绝。服务端规则是:对带陈旧 nonce 的请求不要回包;nonce 在更新的响应出现后变旧。

推论:客户端可以发出多个 DiscoveryRequest,并不期望每个请求都有对应 Response


三、ACK / NACK:协议层承诺边界

协议要求:客户端应对每条 DiscoveryResponse 回 ACK 或 NACK;用 response_nonce 指明在回哪一次推送。

信号 判定 含义(协议原文口径)
ACK error_detailversion_info 取响应中的版本 各资源单独看有效,客户端意图应用
NACK error_detailversion_info 为客户端仍在用的版本 至少一个资源无效

官方钉死的两句话必须拆开读:

  1. ACK 只表示「隔离校验通过并打算应用」不保证配置已成功落到可服务状态;ACK 之后仍可能应用失败。
  2. NACK 不表示「本批全部拒绝」;细节在 error_detail.message

检测 NACK 的首选方式是看 error_detail 是否存在。仅靠「nonce 对应的版本与请求 version 不一致」推断 NACK,在 RDS/EDS 等会动态改订阅集合的 API 上会误判——除非服务端每次订阅变更都抬版本。

sequenceDiagram
  participant CP as ControlPlane
  participant E as Envoy
  CP->>E: DiscoveryResponse V=X nonce=A
  alt all resources valid in isolation
    E->>CP: DiscoveryRequest V=X nonce=A ACK
  else at least one invalid
    E->>CP: DiscoveryRequest V=prev nonce=A NACK error_detail
  end

与流量的关系:ACK 落在「协议接受」;Listener/Cluster 是否 warming 完成、Worker 快照是否已切、新 RDS 是否已对请求可见,是下一层状态机——见 第 11 篇。把控制面「看到 ACK」当成「金丝雀已吃到新路由」,是联调第一大误区。


四、NACK 之后:失败模式清单

场景 数据面行为 控制面若处理不当
单资源非法(字段/PGV/未知 type) NACK;继续跑上一有效版本 反复推同一坏版本 → 无意义 CPU;应修资源或抬到可 ACK 的 Y
SotW 响应重复同名资源 客户端应 NACK 修打包逻辑
流断开 重连;nonce 失效;带已知 version 勿假设旧 nonce 仍有效
文件系统订阅 ACK/NACK 通道;坏更新拒收后保留上一有效配置 只能看 stats/日志
ACK 后应用失败 协议已 ACK,运行时可能仍旧配置或进入异常路径 只盯 ACK 计数会漏掉真实故障;需对照 admin / stats

NACK 不会自动回滚「已经原子切换成功」的监听器——它拒绝的是这一次协议更新。旧配置继续服务,直到出现可 ACK 且可应用的新版本(或进程级变更,见 第 12 篇)。

分类型流上的额外风险:最终一致窗口。RDS 已指向 cluster Y,而 CDS/EDS 尚未提供 Y,会出现短暂黑洞。协议文档的 make-before-break 顺序是:CDS → EDS → LDS → RDS →(再删陈旧 CDS/EDS)。ADS 降低「多服务端抢序」难度,但不免除控制面自己按该顺序推送的责任。


五、争论与开放问题

争论 A B 工程落点
SotW vs Incremental 实现与推理简单 大规模 EDS 带宽与尾延迟 Mesh 控制面普遍走向 Delta;小集群 SotW 仍可接受
分类型流 vs ADS 可拆管理端、故障隔离 排序与一致性 要严格 make-before-break 时优先 ADS
ACK 作为「配置已生效」SLI 控制面易观测 漏掉 warming / 应用失败 SLI 应叠 warming 与路由命中,而非单看 ACK

开放问题(可检验):在超大规模 endpoint churn 下,Incremental ADS 的控制面内存(每客户端订阅状态)与 SotW 重推成本,哪一侧先成为瓶颈——需要按具体控制面实现与订阅基数实测,本篇不给未跑数字。


六、参考资料

规范 / 官方文档(A)

源码(A)

站内对照

实验台账


七、小结

  1. 四个变体由 SotW/Delta 与分类型流/ADS 正交组合;ADS 服务排序,Incremental 服务规模。
  2. version_info 是类型级时钟;nonce 是流内配对时钟——混用会误判 NACK。
  3. ACK = 隔离校验通过并意图应用,不等于 warming 完成或流量已切。
  4. NACK 后旧配置继续服务;危险在于控制面空转坏版本,以及分类型流上的最终一致黑洞。

系列目录 · 上一篇:xDS 资源树 · 下一篇:Warming、SDS 与热更新

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .