【kube-apiserver】Watch 路径(服务端):长连接、410 Gone 与 timeout
内容提要
本文介绍Kubernetes v1.30.3中apiserver的Watch服务端路径,涵盖建立流程、resourceVersion语义(0与具体RV差异)、410 Gone的两大来源(cacher ring buffer滑出窗口或etcd ErrCompacted上浮)及分列方法、timeout与连接生命周期(含bookmark作用),并说明与client-go Informer的边界及WatchList功能现状。
延伸解读
410 Gone 的两种成因与排查方向
客户端收到 410 Gone 时,可能来自 cacher ring buffer 滑出窗口,也可能来自 etcd ErrCompacted 上浮。前者通常与集群写入速率突然升高有关,后者常在 etcd compaction 刚执行后出现。若多资源类型同时 410,更可能是共享 etcd compaction 事件;若仅单一资源,则更可能是该资源 cacher 的 ring buffer 被覆盖。区分成因有助于针对性调整 cacher 配置或 etcd compaction 策略。
resourceVersion=0 与空值的差异
Watch 请求中 resourceVersion 为空时,apiserver 直接从当前时刻推送增量事件,不回放历史;而 resourceVersion=0 时,cacher 会先发送内存 store 的全量 ADDED 事件,再转入增量推送。client-go Reflector 通常使用 rv=0 发起初始 Watch,以获取全量快照。理解这一差异有助于排查客户端初始同步行为,避免误以为数据丢失。
timeout 与 bookmark 对连接生命周期的影响
Watch 连接的生命周期受 timeoutSeconds 控制,默认约 1800 秒,到期后 apiserver 主动关闭连接。bookmark 事件约每 60 秒推送一次,不仅用于同步进度,还能保持连接活跃,防止负载均衡器因长时间无数据而断开。若客户端频繁断连,可检查是否未处理 bookmark 或 timeout 设置过短。
Q&A
Kubernetes apiserver 中 Watch 请求的 resourceVersion=0 与不指定 resourceVersion 有什么区别?
resourceVersion=0 时,apiserver 会先发送 cacher 内存 store 的全量 ADDED 事件(即全量快照),然后切换到增量推送;而不指定 resourceVersion(空字符串)时,apiserver 不会回放历史,直接从当前时刻开始推送新事件。
Kubernetes 中 410 Gone 错误可能由哪些原因引起?如何区分?
410 Gone 可能由两个原因引起:一是 cacher 的 ring buffer 滑出窗口,无法回放指定 resourceVersion 之后的事件;二是底层 etcd 返回 ErrCompacted,即 etcd 侧 compaction 裁掉了相关 revision。区分方法:如果集群写入速率突然升高,可能是 ring buffer 被覆盖;如果 etcd compaction 刚执行,可能是 ErrCompacted;如果多种资源类型的 Watch 同时 410,更可能是 etcd compaction 导致。
Kubernetes apiserver 中 Watch 连接的超时是如何控制的?bookmark 事件有什么作用?
Watch 连接的超时由客户端指定的 timeoutSeconds 控制,到期后 apiserver 主动关闭连接;如果不指定,则使用 apiserver 的默认值(--min-request-timeout,默认 1800 秒)。--request-timeout 是进程级全局超时,对 Watch 不直接适用。bookmark 事件定期推送(默认约 60 秒),用于保持连接活跃,防止负载均衡器等中间设备因长时间无数据而断开连接。
Kubernetes apiserver 中 Watch 请求是如何建立的?底层存储是 cacher 时如何处理?
客户端发送 GET 请求并带 watch=true 参数,REST handler 识别后进入 Watch 路径,解析 ListOptions,然后调用 registry 的 Watch(),最终调用 storage 的 Watch()。如果底层存储是 Cacher,则走 cacher.Watch();如果 Cacher 不可用或配置直连,则走 etcd3 store.Watch()。之后将 Watch channel 对接成 HTTP 长连接,逐事件序列化后 flush 给客户端。
Kubernetes 中 client-go Informer 如何处理 410 Gone 错误?
client-go Informer 收到 410 Gone 后,会重新执行 List(通常使用 rv=0)获取全量快照,然后以当前 resourceVersion 重新发起 Watch,续接增量。这是标准的恢复流程。
Kubernetes 中 WatchList 功能是什么?在 v1.30.3 中状态如何?
WatchList(KEP-3157)是 Kubernetes 社区提出的替代方向,目的是减少 List 的全量数据传输,同时在服务端控制 Watch 连接生命周期。在 v1.30.3 中,该功能仍处于 feature gate(WatchList=true)阶段,生产稳定性尚待观察。