中文内容
Kubernetes v1.36:服务端分片 List 和 Watch
随着 Kubernetes 集群增长到数万节点,监视 Pod 等高基数资源的控制器会遇到扩展瓶颈。水平扩展控制器的每个副本都会从 API server 接收完整事件流,并为反序列化所有内容付出 CPU、内存和网络成本,最后只丢弃那些不属于自己负责范围的对象。扩展控制器并不会降低每个副本的成本;反而会将成本成倍放大。
Kubernetes v1.36 将服务端分片 list 和 watch 作为 alpha 特性引入(KEP-5866)。启用该特性后,API server 会在源头过滤事件,使每个控制器副本只接收其所拥有的资源集合切片。
客户端分片的问题
一些控制器,例如 kube-state-metrics,已经支持水平分片。每个副本会被分配一部分键空间,并丢弃不属于它的对象。虽然这在功能上可行,但并不会减少从 API server 流出的数据量:
- N 个副本 x 完整事件流:每个副本都会反序列化并处理每个事件,然后丢弃不需要的内容。
- 网络带宽随副本数扩展,而不是随分片大小扩展。
- 用于反序列化的 CPU 会浪费在被丢弃的那部分数据上。
服务端分片 list 和 watch 通过将过滤上移到 API server 来解决这一问题。每个副本告知 API server 自己拥有哪个哈希范围,API server 只发送匹配的事件。
工作原理
该特性向 ListOptions 添加了 shardSelector 字段。客户端使用 shardRange() 函数指定一个哈希范围:
shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')
API server 会对指定字段计算确定性的 64 位 FNV-1a 哈希,并仅返回哈希落在 [start, end) 范围内的对象。这同时适用于 list 响应和 watch 事件流。该哈希函数在所有 API server 实例上产生相同结果,因此该特性可安全用于多个 API server 副本。
当前支持的字段路径为 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
}),
)
对于 2 副本部署,选择器会将哈希空间一分为二:
// 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')"
单个副本也可以使用 || 覆盖非连续范围:
"shardRange(object.metadata.uid, '0x0000000000000000', '0x4000000000000000') || " +
"shardRange(object.metadata.uid, '0x8000000000000000', '0xc000000000000000')"
验证服务端支持
当 API server 接受分片选择器时,list 响应会在响应元数据中包含 shardInfo 字段,用于回显已应用的选择器:
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "10245",
"shardInfo": {
"selector": "shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"
}
},
"items": [...]
}
如果 shardInfo 缺失,则表示服务器未接受分片选择器,客户端收到的是完整且未过滤的集合。在这种情况下,客户端应准备好处理完整结果集,例如通过应用客户端过滤来丢弃其分配分片范围之外的对象。
参与其中
该特性目前处于 alpha 阶段,需要在 API server 上启用 ShardedListAndWatch 特性门控。我们正在征求来自控制器作者以及运行大型集群的运维人员的反馈。
- KEP-5866:服务端分片 List 和 Watch
- API 概念:分片 list 和 watch
- 正文:SIG API Machinery
如果你有问题或反馈,请加入 Kubernetes Slack 上的 #sig-api-machinery 频道。
- ← 上一篇
- 下一篇 →