Kubernetes v1.36:服务端分片列表与监听

原文链接:https://kubernetes.io/blog/2026/05/06/kubernetes-v1-36-server-side-sharded-list-and-watch/


随着 Kubernetes 集群增长到上万个节点,监视 Pod 等高基数资源的控制器会面临扩展瓶颈。水平扩展的每个控制器副本都会从 API 服务器接收完整的事件流,为反序列化所有数据付出 CPU、内存和网络开销,却只为了丢弃那些它不负责的对象。增加控制器副本并不能降低单个副本的代价,反而会成倍增加。

Kubernetes v1.36 引入了**服务端分片列表与监视(server-side sharded list and watch)**作为 alpha 特性(KEP-5866)。启用该特性后,API 服务器会在数据源头过滤事件,使每个控制器副本只收到它所属的那部分资源集合。

客户端分片的问题

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

  • N 个副本 × 完整事件流:每个副本都要反序列化并处理每个事件,然后丢弃不需要的部分。
  • 网络带宽随副本数线性增长,而非随分片大小增长。
  • 用于反序列化的 CPU 对丢弃的部分来说是被浪费的。

服务端分片列表与监视通过将过滤操作上移至 API 服务器来解决此问题。每个副本告诉 API 服务器它拥有哪个哈希范围,API 服务器只发送匹配的事件。

工作原理

该特性在 ListOptions 中新增了一个 shardSelector 字段。客户端使用 shardRange() 函数指定一个哈希范围:

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

API 服务器会计算指定字段的确定性 64 位 FNV-1a 哈希值,并仅返回哈希值落在范围 [start, end) 内的对象。此逻辑同时适用于列表(list)响应和监听(watch)事件流。该哈希函数在所有 API 服务器实例上产生相同的结果,因此该特性可以在多个 API 服务器副本中安全使用。

当前支持的字段路径(field path)为 object.metadata.uidobject.metadata.namespace

在控制器中使用分片监听

控制器通常使用 informer(通知器)来列出和监听资源。为了将工作负载分片(shard),每个副本通过 WithTweakListOptionsshardSelector 注入到其 informer 所使用的 ListOptions 中:

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

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

factory := informers.NewSharedInformerFactoryWithOptions(client, resyncPeriod,
    informers.WithTweakListOptions(func(opts *metav1.ListOptions) {
        opts.ShardSelector = shardSelector
    }),
)
</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>对于一个 2 副本(2-replica)部署,选择器将哈希空间一分为二:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>// Replica 0: lower half of the hash space
"shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"

```markdown
// 副本1:哈希空间的上半部分
"shardRange(object.metadata.uid, '0x8000000000000000', '0x10000000000000000')"

单个副本也可以使用 || 覆盖非连续范围:

“shardRange(object.metadata.uid, ‘0x0000000000000000’, ‘0x4000000000000000’) || ” +”shardRange(object.metadata.uid, ‘0x8000000000000000’, ‘0xc000000000000000’)”


## 验证服务器支持

当 API 服务器支持分片选择器(shard selector)时,列表响应会在元数据中包含一个 `shardInfo` 字段,该字段会回显已应用的选择器:

{“kind”: “PodList”,”apiVersion”: “v1″,”metadata”: {“resourceVersion”: “10245”,”shardInfo”: {“selector”: “shardRange(object.metadata.uid, ‘0x0000000000000000’, ‘0x8000000000000000’)”}},”items”: […]}


如果`shardInfo`缺失,说明服务器未遵循分片选择器(shard selector),客户端接收到了完整且未经筛选的集合。在这种情况下,客户端应做好处理完整结果集的准备,例如通过应用客户端过滤机制来丢弃其分配分片范围之外的对象。

## 参与进来

该功能仍处于Alpha阶段,需要在API服务器上启用`ShardedListAndWatch`特性门控(feature gate)。我们期待来自控制器开发者以及运行大型集群的运维人员的反馈。

-   [KEP-5866:服务端分片列表与监听(Server-Side Sharded List and Watch)](https://github.com/kubernetes/enhancements/issues/5866)
-   [API概念:分片列表与监听(Sharded list and watch)](https://kubernetes.io/docs/reference/using-api/api-concepts/#sharded-list-and-watch)
-   [SIG API Machinery](https://github.com/kubernetes/community/tree/master/sig-api-machinery)

如有疑问或反馈,请加入[Kubernetes Slack](https://slack.k8s.io/)的`#sig-api-machinery`频道。