Day 10 / 共 20 天 · 第 2 周收官

代理连接生命周期

把第 2 周串成一个完整故事:一个 Envoy 从连上 istiod、拿初始配置、收增量更新、到断开的全过程。这是控制面和数据面协作的端到端复盘。收官第 2 周。

📍 你在控制面 istiod 之旅的位置(第 2 周收官:把前 9 天串成一个 Envoy 从生到死的完整故事)
D1 全景· D2 启动· D3 配置CRD· D4 服务注册· D5 快照· D6 xDS服务· D7 生成· D8 Builder· D9 推送· D10 连接
L01

全景六阶段

🤔 痛点:前 9 天的零件都认识了,但拼不成一台机器 你学了 ADS 流、生成器、Builder、debounce、PushQueue……每个都懂,可"一个 Envoy 从开机到关机到底怎么和 istiod 互动"还是串不起来。零件全在,缺一张装配总图。
💡 本质:跟着"一个保安上岗到下岗"走一遍 今天用第一人称请求之旅的方式:你就是一个新入职的门店保安(Envoy)。你会经历报到(连上 istiod)→ 出示工牌自我介绍(首请求 Node.Id)→ 领取完整岗位手册(初始配置)→ 收到规章变更通知(增量更新)→ 名单实时刷新(端点变化)→ 离职交接(断开清理)。把这六幕演一遍,前 9 天的零件就自动拼成一台运转的机器。
建立连接:Envoy 拨号 istiod :15012 ADS gRPC
首请求初始化:报 Node.Id → 解析 model.Proxy + 算 SidecarScope
初始配置下发:Envoy 请求 CDS/LDS/EDS/RDS → istiod 生成并 Send
增量更新:配置变 → debounce → Push → 只推相关 proxy
端点高频更新:Pod 扩缩容 → EDS 独立快路径
断开清理:流关闭 → 从连接表移除
读法:这六阶段把 Day 06(连接/流)+ Day 07-08(生成)+ Day 09(推送)全串起来了。能讲清这个故事,就真正掌握了 istiod 的运行时。
①连接:15012 ②首请求Node.Id ③初始下发C-E-L-R-S ④增量配置变 ⑤端点EDS快路径 ⑥断开清理 ④⑤在服役期间反复发生
一个 Envoy 的一生:连接→自我介绍→领手册→(反复)收变更/刷端点→下岗清理。
L02

① 建立连接

Envoy(经 pilot-agent,Day 12)拨号 istiod :15012(mTLS)或 :15010(明文)的 ADS gRPC,调 StreamAggregatedResourcesads.go:182)。ready/限流/认证通过后 newConnectionxds.Stream(con),起 Receive 协程,阻塞等首请求(Day 06)。

读法:连接建立要过 Day 06 的三道关(ready/限流/认证)。此时连接还没注册进活跃表——要等首请求初始化完(下一步)。
L03

② 首请求初始化

# Receive 收到首请求(必带 Node.Id)→ initConnection(ads.go:239):
#   initProxyMetadata:解析 node id → model.Proxy
#   proxy.LastPushContext = globalPushContext()  # 保证 push context 单调
#   addCon 注册进 adsClients(此后才被 push 遍历到)
#   computeProxyState:算 SidecarScope/Gateway/labels(Day 05)
#   MarkInitialized() → 主循环开始服务
初始化的时序竞态(一个真实工程细节) 注意 addCon(注册进连接表)和 initializeProxy(算 proxy 状态)的顺序很讲究——注释(ads.go:265-269)专门解释了这个竞态。如果先注册再初始化,可能有推送来了但 proxy 状态还没算好;如果先初始化再注册,可能初始化期间的配置变更漏掉。Istio 的处理保证了"注册后一定能被推、且推的时候状态已就绪"。这种时序细节是分布式系统里最容易出 bug 的地方——读源码时看到这类注释要格外留意,它们往往是踩过坑的经验结晶。
L04

③ 初始配置下发

Envoy 依次发 CDS/LDS/EDS/RDS 请求;主循环从 reqChan 取出 → processRequestShouldRespond 判定"初始请求"(Day 06)→ pushXds → 对应 Generator(Day 07-08)→ BuildClusters/BuildListeners… → Send。Envoy 收到后回 ACK。

读法:初始下发有严格顺序(PushOrderads.go:499):CDS → EDS → LDS → RDS → SDS——因为 Envoy 有依赖(Listener 引用 Route、Route 引用 Cluster、Cluster 引用 Endpoint)。先发被依赖的,再发依赖它的,否则 Envoy 会收到"引用了还不存在的资源"的配置。每次下发 Envoy 都回 ACK(带 nonce)。
📝 举个例子:为什么顺序是 CDS→EDS→LDS→RDS 想成"搭积木必须从地基往上搭":
Cluster(后端池)是地基 → 先发(CDS)
Endpoint(池里的机器)填进 Cluster → 再发(EDS)
Listener(门)会引用 Route → 发(LDS)
Route(路牌)会指向 Cluster → 最后发(RDS)
反过来先发 Route,它指向的 Cluster 还不存在 → Envoy 拿到"悬空引用",流量瞬间黑洞。这就是 PushOrder 存在的意义。
💬 记忆口诀 "先建楼后挂牌":Cluster 是楼、Endpoint 是住户、Listener 是大门、Route 是门牌。楼和住户先就位(CDS/EDS),再装门挂牌(LDS/RDS),最后发工牌(SDS)。顺序错了就有人对着不存在的门牌找路。
L05

④ 增量更新

集群里某 VirtualService 变更 → configHandler → ConfigUpdatepushChannel → debounce(100ms 合并)→ Push(全量时重算/复用 PushContext)→ AdsPushAll → StartPush 遍历所有连接入 PushQueue(Day 09)。

doSendPushes 出队 → Event 送入连接 pushChannel → 主循环 pushConnectionProxyNeedsPush 判该 proxy 相关否 → 相关则按 PushOrder 逐类型 pushXds。Envoy 再 ACK。

读法:这就是 Day 09 的推送链在"一次真实变更"里的走位。关键:ProxyNeedsPush 让不相关的 proxy 被跳过——改 payment 的路由,只有调用 payment 的 Envoy 收到更新。
L06

⑤ 端点高频更新

Pod 扩缩容 → EDSUpdateeds.go:47)更新 endpoint 分片 → 触发 push;EDS 走独立缓存路径(Day 07),多数情况只重算该 service 的 ClusterLoadAssignment,且可 SotW 下增量推送(Day 06 通配/非通配)。

读法:端点变化不重算 PushContext(Day 05),走 EDS 快路径。这是"最高频操作专门优化"的体现——Pod 扩缩容是集群里最频繁的事件,必须轻量处理。
L07

⑥ 断开清理

流关闭 → Receive 返回 → Stream 退出 → defer ctx.Close()closeConnectionads.go:283):removeConadsClients 删除 + WorkloadEntryController.OnDisconnect

VM 自动注册随连接生命周期 有个巧妙联动:VM(虚拟机工作负载)通过 WorkloadEntry 自动注册——连上 istiod 时 OnConnect 创建 WorkloadEntry(表示"这个 VM 上线了"),断开时 OnDisconnect 清理("VM 下线了")。于是 VM 的生命周期和它的 xDS 连接绑定——连着就在网格里,断了就自动摘除。这让非 K8s 的 VM 也能像 Pod 一样被自动管理(Day 04 的 K8s+VM 混合网格)。断开清理不只是删连接,还要处理这些副作用。
L08

第 2 周收官 🎓

🧠 第 2 周(xDS 生成)你已掌握

  • Day 06 DiscoveryServer:ADS 流、收发分离、ShouldRespond 状态机
  • Day 07 配置生成:ConfigGenerator、生成器薄封装、EDS 独立路径
  • Day 08 三大 Builder:Listener/Cluster/Route 怎么构造 Envoy 对象
  • Day 09 Push 模型:ConfigUpdate → debounce → PushQueue → 三级优化
  • Day 10 连接生命周期:连接→初始化→初始下发→增量→端点→断开

你现在完全理解了 istiod 的核心——怎么把配置翻译成 xDS 并高效推送给每个 Envoy。第 1 周(数据基础)+ 第 2 周(xDS 生成)= istiod 控制面的完整闭环。第 3 周(已学)讲 sidecar 落地与安全,第 4 周讲遥测、EnvoyFilter、安装。

✋ 动手

cd /Users/bitmart/work/codes/github/higress-group/istio
grep -n 'func.*initConnection\|func.*closeConnection\|PushOrder' pilot/pkg/xds/ads.go
sed -n '445,476p' architecture/networking/pilot.md   # 连接生命周期文档
下一步 · Day 16(第4周):第 3 周(Day 11-15 sidecar/安全)你已学过。接下来第 4 周 遥测——Istio 怎么采集 metrics/trace,Telemetry API 怎么翻译成 Envoy stats filter。
← Day 09 Push 模型 Day 16 · 遥测 →