Kubernetes v1.36:服务端分片 List 与 Watch

当 Kubernetes 集群增长到数万个节点时,监听 Pod 等高基数资源的控制器会遇到扩展瓶颈。水平扩展后的每个控制器副本都会接收 API 服务器的完整事件流,为反序列化所有对象付出 CPU、内存和网络开销,随后又丢弃不由自己负责的对象。增加控制器副本并不会降低每个副本的成本,反而会让总成本成倍增加。

Kubernetes v1.36 引入了处于 Alpha 阶段的服务端分片 List 与 Watch 功能,见 KEP-5866。启用后,API 服务器在源头过滤事件,使每个控制器副本只接收由自己负责的那一部分资源集合。

客户端分片的问题

一些控制器,例如 kube-state-metrics,已经支持水平分片。每个副本被分配一部分键空间,并丢弃不属于它的对象。这在功能上可行,却不能减少从 API 服务器流出的数据量:

  • N 个副本各自接收完整事件流:每个副本都会反序列化和处理每个事件,然后丢弃自己不需要的部分。
  • 网络带宽需求随副本数量增长,而不是随每个分片的大小变化。
  • 用于反序列化被丢弃对象的 CPU 时间被浪费了。

服务端分片 List 与 Watch 将过滤操作上移到 API 服务器。每个副本告诉服务器自己负责的哈希范围,服务器只发送匹配的事件。

工作原理

该功能在 ListOptions 中增加了 shardSelector 字段。客户端使用 shardRange() 函数指定哈希范围:

shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')

API 服务器对指定字段计算确定性的 64 位 FNV-1a 哈希,只返回哈希落入 [start, end) 范围的对象,即包含起点、不包含终点。此规则同时适用于 List 响应和 Watch 事件流。所有 API 服务器实例会得到相同的哈希结果,因此可用于拥有多个 API 服务器副本的集群。

当前支持的字段路径为 object.metadata.uid 和 object.metadata.namespace。

在控制器中使用分片 Watch

控制器通常使用 informer 列举和监听资源。要对工作负载分片,每个副本通过 WithTweakListOptions,将 shardSelector 注入 informer 使用的 ListOptions:

import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/informers"
)

shardSelector := "shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"

factory := informers.NewSharedInformerFactoryWithOptions(client, resyncPeriod,
    informers.WithTweakListOptions(func(opts *metav1.ListOptions) {
        opts.ShardSelector = shardSelector
    }),
)

对于包含两个副本的部署,选择器将哈希空间等分为两半:

// Replica 0: lower half of the hash space
"shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"

// Replica 1: upper half of the hash space
"shardRange(object.metadata.uid, '0x8000000000000000', '0x10000000000000000')"

其中,副本0负责哈希空间的下半部分,副本1负责上半部分。单个副本也可以使用 || 覆盖多个不连续范围:

"shardRange(object.metadata.uid, '0x0000000000000000', '0x4000000000000000') || " +
    "shardRange(object.metadata.uid, '0x8000000000000000', '0xc000000000000000')"

确认服务器是否支持

API 服务器实际采用分片选择器时,List 响应的元数据中会包含 shardInfo 字段,回显已应用的选择器:

{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "10245",
    "shardInfo": {
      "selector": "shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"
    }
  },
  "items": [...]
}

如果缺少 shardInfo,就说明服务器没有采用分片选择器,客户端收到的是完整、未过滤的集合。此时客户端应能够处理完整结果集,例如在客户端执行过滤,丢弃不属于自身分片范围的对象。

参与反馈

该功能处于 Alpha 阶段,需要在 API 服务器上启用 ShardedListAndWatch 特性门控。项目希望收到控制器作者和大规模集群运维人员的反馈。

如有问题或反馈,可加入 Kubernetes Slack 的 #sig-api-machinery 频道。


原文:Kubernetes v1.36: Server-Side Sharded List and Watch。作者:Jeffrey Ying(Google);发表于2026年5月6日。本文为中文翻译,保留原文1.36 Alpha版本范围。原文网站仓库采用 CC BY 4.0。代码与命令仅依据原文核对,未在集群中运行。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容