SharedInformer 会压垮 API Server 因其默认全量 List+Watch,未过滤时触发 etcd 高频读与高 CPU;须用 fieldSelector 从源头过滤、禁用 ResyncPeriod、复用 SharedInformerFactory。

SharedInformer 为什么反而会压垮 API Server
默认 SharedInformer 启动时会执行一次全量 List,再持续 Watch。如果你没做任何过滤,它就等价于对整个集群该资源类型做“全表扫描”——比如监听 Pods 但不指定命名空间,API Server 就得把所有 namespace 下的数万 Pod 全部序列化返回,再维持一个长连接推送变更。这不仅吃带宽、占内存,还会触发 etcd 高频读,尤其在节点数 >500 的集群里,单个 Informer 就可能让 apiserver 的 CPU 持续超 70%。
必须在 ListWatch 层加 fieldSelector 过滤
不能靠 OnAdd 回调里手动跳过非目标 namespace 的对象——那样对象早已被缓存、索引、监听,内存和事件队列压力一点没少。真正有效的过滤必须从源头掐断:
- 用
fields.OneTermEqualSelector("metadata.namespace", "default")构造 selector - 在自定义
cache.ListWatch的ListFunc和WatchFunc中,都显式设置options.FieldSelector = selector.String() - 确保 Kubernetes API Server 版本 ≥1.21(旧版本需确认是否启用
--runtime-config=api/all=true) - 命名空间参数仍传空字符串
"",因为过滤逻辑已交给FieldSelector,不是靠 clientset 路径
禁用 ResyncPeriod + 谨慎使用 Indexers
ResyncPeriod 设为非零值(如 30 分钟)会导致 Informer 定期重新 List 所有已过滤的对象,并重建整个缓存——这等于每半小时来一次“小规模全量同步”,对内存和 API Server 都是重复冲击。生产环境应设为 0 禁用。
自定义 Indexers(比如按 label 或 annotation 建索引)虽能加速查询,但每个索引都额外维护一份 map,对象越多、索引越多,内存占用呈线性增长。只在真有高频查询需求时才加,且避免嵌套结构或大字段做 key。
立即学习“go语言免费学习笔记(深入)”;
用 SharedInformerFactory 复用而非手搓多个 Informer
多个控制器若监听同一资源(如都看 ConfigMap),各自 new 一个 Informer,就会建立多个独立的 ListWatch 连接,造成冗余请求。正确做法是共用一个 informers.NewSharedInformerFactory(clientset, 0) 实例,再通过 .Core().V1().ConfigMaps().Informer() 获取引用——底层 Watch 连接、DeltaFIFO、Indexer 缓存全部共享,只增不减。
容易忽略的一点:SharedInformerFactory 的 ResyncPeriod 参数传 0 才能全局禁用 resync;如果 factory 初始化时传了 30*time.Minute,即使你后面调 Informer().AddEventHandler,它依然会周期性重同步。


















