第 24 章 大规模集群性能调优:万节点是一场对”设计假设”的清算

墨:前面 23 章,我们一直默认一件事——集群”足够小”,小到 etcd 不会喘、API Server 不会卡、一个 watch 连接无关痛痒。可一旦节点数越过几千、逼近上万,你前面学的每一套优雅设计,都会反过来咬你一口。

你:等等,设计不就是设计吗?小集群大集群难道不是同一个 K8s?

墨:同一个 K8s,但不一样的规模,逼出不一样的结构。规模不是”量变”,它是把隐含假设一条条拎出来、贴脸上问你”你还认不认”的照妖镜。比如控制循环假设”状态变化能被及时 watch 到”——万节点下,单个 watch 连接的事件洪流能把内存和带宽吃光;声明式 API 假设”每次 reconcile 都能轻量读全量”——万节点下,光把 NodeList 拉一遍就够喝一壶。这章,我们就来清算这些假设。


24.1 先问对问题:万节点到底”难”在哪

很多人的第一反应是”加机器呗”。加机器解决的是算力,解决不了结构性瓶颈——那些瓶颈来自 K8s 自身的设计,加 CPU 加内存都没用。

墨:你先自己盘一下,万节点集群里,哪些东西的”数量”会爆炸式增长?

你:节点 1 万、Pod 可能几十万、Service 成千上万、Endpoint 对象……

墨:对,但更致命的是它们之间的”关系乘积”。1 万个 Service,每个 Service 背后 10 个 Pod 端点,就是 10 万条端点映射。任何一个 Pod 重建,都得更新它归属的那些 Service 的 Endpoints。于是”一个 Pod 变”会触发”多条 Endpoints 变”,而每条 Endpoints 变又会触发”所有 watch 它的 kube-proxy 收到通知”。这个扇出(fan-out),不是线性,是指数级的连锁。

我们把它拆成五类”规模原罪”:

① etcd 写入瓶颈。所有状态变更最终都落 etcd。万节点下,Pod 调度、状态上报、Endpoint 更新、Lease 心跳,写流量惊人。etcd 是 CP 系统(第 5 章讲过),强一致意味着每次写入都要走 Raft、要多数派确认。它扛不住无节制的写。

② watch 扇出 / API Server 内存爆炸。每个 kube-proxy、每个控制器、每个 Informer 都持有一个 watch 长连接。对象一变更,API Server 要把这个变更推给所有订阅者。N 个对象 × M 个 watch 连接 = N×M 的推送矩阵。万节点下这个矩阵的规模能让 API Server 内存和网卡同时崩。

③ 全量 LIST 风暴。Informer 启动要先 LIST 全量再 WATCH 增量(第 3 章讲过 level-triggered)。万节点下,一个控制器 LIST 一次 NodeList 就是 1 万个对象,几十个控制器同时 LIST,API Server 的 CPU 和 etcd 的读压力瞬间打满。更糟的是”惊群”——所有 kube-proxy 差不多同时重启,同时 LIST 所有 Service/Endpoints,形成周期性的读风暴。

④ 对象数量本身。每个 Pod 一个 Endpoint 对象(旧模型),几十万 Pod 就是几十万 Endpoints 对象躺在 etcd 里,每次 compaction、每次备份、每次 watch 重建都是成本。

⑤ 单点路径的串行化。调度器是单实例串行调度的(虽然有多线程,但同一个 Pod 只在一个 cycle 里决策);控制器管理器里很多控制器也是串行 reconcile。对象多了,处理延迟线性拉长。

墨:你看,这五条里,没有一条是”加机器”能直接救的。etcd 是 CP 你没法定制它的写入语义;watch 扇出是架构决定的;LIST 风暴是 Informer 机制的副产物。所以”规模调优”的本质,是在不破坏 K8s 设计哲学的前提下,把扇出、写放大、LIST 风暴这些副产物压下去。

⚠️ 坑:别一上来就调 --max-requests-inflight。那是治标。真正的调优顺序是:先压写放大(etcd 层)→ 再压扇出(watch 层)→ 再压 LIST 风暴(Informer/缓存层)→ 最后才是参数微调。顺序错了,参数调到天上去也救不了。


24.2 etcd 层:先把”写”这个最贵的动作管住

etcd 是万节点集群的”心脏起搏器”,但它也是第一个到瓶颈的。调优 etcd,核心就一句话:少写、分批写、分开存、用快盘。

24.2.1 拆库:对象与事件分离

K8s 里最”吵”的对象是什么?是 Event。一个 Pod 启动失败、被 OOM、被驱逐、被探针打死……都会产生 Event。万节点下,Event 的写入量可能占到 etcd 总写的一半以上,而且 Event 是高频、短命、可丢弃的——你真需要把”三天前的 Warning”强一致地存进 CP 存储吗?

墨:你觉得 Event 该不该和 Pod 放同一个 etcd?

你:不该。Event 丢了顶多排障少条线索,Pod 丢了是状态没了。两者的一致性要求完全不同。

墨:正是。K8s 社区的解法(KEP-2094,1.19+ 成熟)是单独的 Event 存储:kube-apiserver 的 --etcd-servers 配主库,另开 --etcd-servers-overrides 把 /events 这个资源前缀指向独立的 etcd 实例。

# kube-apiserver 启动参数(示意)
--etcd-servers=https://etcd-main:2379
--etcd-servers-overrides=/events#https://etcd-events:2379

这样,吵闹的 Event 写流量被隔离到第二套 etcd,主库只扛”正经状态”。主库的写压力、磁盘 IO、Raft 日志量立刻腰斩。

📦 案例:某厂 5000 节点集群,未拆 event 时主 etcd 写入峰值 8k QPS,P99 写入延迟 120ms,偶发 leader 切换。拆到独立 event etcd 后,主库写入降到 3k QPS,P99 写入延迟 35ms,再没出现因写入压力导致的 leader 切换。

24.2.2 降写:Lease 代替 NodeStatus 心跳

你以为节点”健康”是靠什么上报的?早期靠 NodeStatus 的 status.conditions 更新——每个节点每 10 秒(默认 --node-status-update-frequency)就 PATCH 一次自己的 Node 对象。1 万节点 = 每秒 1000 次 Node 对象写入。而这些写入几乎永远是同一个字段的同一个值(节点没挂就不会变)。

墨:一个”没变化”的状态,每 10 秒写一次 etcd,你觉得这种写值不值得?

你:不值。状态没变,写它干嘛?纯浪费。

墨:K8s 的演化解法(KEP-579,1.17+ 默认开启)是引入 Lease 对象:每个节点在 kube-node-lease 命名空间里有一个自己的 Lease,节点只需更新 Lease 的 spec.renewTime(一个极小的对象)。节点是否存活,由”Lease 最近刷新时间”判断,而不是去读 Node 的大对象。

这带来两个收益:

  • 写放大骤降:Lease 对象几十字节,Node 对象几百字节还带一堆字段。同样”我活着”的心跳,写 Lease 比写 Node 便宜一个数量级。
  • Node 对象稳定:Node 的调度相关字段(capacity、allocatable、labels)不再被高频心跳 PATCH 冲刷,降低了对 Node 对象的 watch 噪声。

24.2.3 快盘与配置:NVMe、配额、压缩

etcd 的瓶颈 80% 在磁盘 IO——Raft 日志要先落盘才能 commit。万节点下,慢盘(云盘、网络盘)的 fsync 延迟会直接拖垮写入吞吐。

  • 用本地 NVMe SSD。etcd 官方明确建议:磁盘顺序写 ≥ 100MB/s、fsync 延迟 < 10ms。云上的网络块存储往往 fsync 在 10-50ms,NVMe 本地盘能到亚毫秒。
  • --quota-backend-bytes:etcd v3 后端默认 2GB 配额。万节点对象量容易逼近,及时调大到 8GB/16GB,否则超出直接拒绝写入,集群雪崩。
  • 自动压缩(compaction):etcd 的 MVCC 保留历史版本,不压缩就只增不减。--auto-compaction-mode=revision --auto-compaction-retention=1(保留最近 1 个版本区间)或按时间 1h。但注意:压缩只打”逻辑删除”标记,还要配 --defrag 或定期 etcdctl defrag 真正回收空间,否则 db 文件只涨不跌。

⚠️ 坑:defrag 是个阻塞且重的操作,会对单个 member 重写整个 db 文件,期间该 member 不可用(多副本下会触发重新选主)。务必轮流 defrag 单节点,且不要和备份同时做。线上曾有人一次 defrag 三节点,集群短暂不可用 2 分钟。

24.2.4 读放大:etcd 的串行化读是隐藏杀手

etcd v3 默认一致性读(quorum read)要多数派确认,贵。但 API Server 对 etcd 的读很多是”watch 的起始 LIST”和”缓存回填”——这些读其实可以容忍”稍微旧一点”。K8s 用 --etcd-compaction-... 之外,还在 API Server 侧把 etcd 当”事实源 + 本地缓存”用(第 4 章讲过,API Server 自己有 watch cache)。真正落到 etcd 的”强一致读”应被压到最少。

演化小结(etcd 层):问题=CP 存储扛不住高频写 → 设计分离=event 独立库 / Lease 代替心跳 / NVMe 快盘 / 压缩回收 → 老问题的新方法=把”吵闹但可丢”的流量请出主库,把”心跳”从大对象降级到小对象。


24.3 API Server 层:它不是”无状态转发器”那么简单

很多人以为 API Server 无状态、多副本就完事。但在万节点下,API Server 是缓存 + 扇出中枢,它的内存和连接管理才是命门。

24.3.1 watch cache:让 API Server 当”读缓存代理”

关键认知:客户端 watch 的不是 etcd,是 API Server;而 API Server 自己也在 watch etcd,并在内存里维护每个资源的”有序缓存”(watch cache)。当 kube-proxy 来 LIST+WATCH 一个 Service,API Server 不用每次都打 etcd——它从自己的 watch cache 返回,并基于缓存版本号续接 watch。

墨:这套”API Server 缓存 + 客户端缓存”的二级缓存,对你有什么启发?

你:读被 API Server 扛住了,etcd 只接收”真正的写”和”API Server 自己的 watch”。客户端成千上万,但打 etcd 的 watch 连接只有”API Server 副本数”那么几个。扇出在 API Server 这里收口了?

墨:说对了。这是 K8s 把”N×M 扇出”化解成”N 客户端 × 少量 API Server,API Server × 1 etcd”的核心机制。但代价是——API Server 内存里要装下所有资源的缓存。万节点下,这个缓存可能几个 GB。所以:

  • --watch-cache-sizes 显式调大高频资源的缓存(如 pods#10000,endpoints#5000,services#2000),避免缓存被挤掉后回退成直接打 etcd。
  • API Server 实例内存要给足(8-16GB 起),别用默认 2GB。

24.3.2 优先级与公平性:priority & fairness(APF)

万节点下最怕什么?一个失控的控制器疯狂 LIST 全量,把 API Server 的 inflight 请求打满,于是 kubelet 上报状态、kube-proxy 更新规则这些关键流量也被拒——整个集群”假死”。

演化解法(KEP-1040,1.18+ GA 叫 Priority and Fairness,APF):API Server 把请求按优先级(PriorityLevel)和流(FlowSchema)分类。默认给系统组件(kubelet、controller、scheduler)高优先级和独立配额;给普通用户的 ad-hoc kubectl get 低优先级。更重要的是公平性——同类请求按流限流,防止一个用户的 100 个并发 LIST 饿死另一个用户的请求。

# 示意:给 system:kubelet 高优先级
apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
kind: PriorityLevelConfiguration
metadata:
  name: system
spec:
  limited:
    nominalConcurrencyShares: 1000   # 高份额
  type: Limited

⚠️ 坑:APF 默认开启后,如果你用了一个很低优先级的 ServiceAccount 去跑高频 LIST 的自定义控制器,会发现请求频繁被限流(429 Too Many Requests)。这不是 bug,是 APF 在保护控制面。正确做法是给该控制器的 FlowSchema 配合适的优先级,而不是关掉 APF。

24.3.3 请求配额与超时

  • --max-requests-inflight / --max-mutating-requests-inflight:限制并发读/写。万节点要调大(如 3000 / 1000),但要注意——这不是越大越好,超过 API Server 处理能力只会堆内存。它该和你的 API Server 规格匹配。
  • --min-request-timeout:watch 的长连接保活。惊群重启时大量 watch 重连,这里别太小。

24.4 扇出治理:EndpointSlice 是”对象爆炸”的头号解药

回到 24.1 的扇出问题。老模型里,一个 Service 对应一个 Endpoints 对象,里面塞满所有 Pod 的 IP:Port。问题:

  1. 一个 Service 的 Endpoints 对象可能几十 KB(上千端点)。
  2. 任一端点变 → 整个 Endpoints 对象重写 → 推给所有 watch 它的 kube-proxy。
  3. 1 万个 Service,每个端点集合变更,都是一次大对象广播。

演化解法(KEP-1063,1.21 GA):EndpointSlice。一个 Service 的后端被切成多个小 EndpointSlice(默认每片最多 100 个端点)。收益:

  • 更新粒度变小:一个 Pod 死,只改它所在的那一片,不碰其他片。广播的数据量从”整个 Service 端点集”降到”一个 100 端点的片”。
  • 多网络寻址:一个 Slice 可带多个 IP 族(IPv4/IPv6)、多种拓扑,老 Endpoints 结构表达力不够。
  • 可水平扩展:Service 后端再多,切片数随之增长,单对象大小恒定。

墨:你品品,EndpointSlice 解决的是”对象爆炸”,用的是哪条方法论?

你:把”一个大对象”拆成”一群小对象”,更新时只动相关的小片——本质是分片(sharding)降低写放大和广播面。

墨:对,就是分片。你会在 K8s 里反复看到这套思路:Endpoints→EndpointSlice 是分片,Node 心跳从 Node→Lease 是”降级小对象”,etcd event 拆库是”分库”。规模逼出的结构优化,套路惊人地一致——把热点大对象打碎。

开启方式:1.21+ 默认 EndpointSlice 由 endpointslice-controller 自动生成,kube-proxy 1.19+ 默认消费 EndpointSlice。只是要确保没人还在依赖老 Endpoints 的 subsets 字段。


24.5 LIST 风暴与 Informer:惊群怎么治

Informer 启动要先 LIST 全量。如果 50 个控制器 + 5000 个 kube-proxy 在同一秒重启,它们同时 LIST 所有 Service/Endpoints/Node——API Server 和 etcd 读压力瞬间爆。

24.5.1 客户端侧的”共享 Informer”与分页

K8s 客户端(client-go)已经做了共享 Informer(SharedInformer):同一个进程里多个控制器 watch 同一资源,只 LIST 一次、只建一个 watch 连接,事件扇出给本地多个 listener。所以”5000 个 kube-proxy”各自是独立进程(没法共享),但”一个控制器管理器里的 30 个控制器”共享一份 LIST。

但跨进程没法共享,于是还有:

  • LIST 分页(chunk):kube-apiserver --target-ram-size 配合客户端的 Limit 分页拉取,避免一次返回 1 万个对象撑爆内存。
  • --http2-max-streams-per-connection:HTTP/2 多路复用下,单连接的并发流上限。

24.5.2 服务端侧的 “watch bookmarks” 与 “进度通知”

API Server 会周期性发 bookmark 事件(不携带数据,只带 resourceVersion),告诉客户端”你已经追到这个版本了”。客户端据此做 checkpoint,重启时从 bookmark 续接而非从头 LIST。这是把”全量 LIST”降级为”增量续传”的关键。

📦 案例:某团队自定义控制器每次重启都 LIST 全量 Endpoints(几百 MB),20 个副本同时 rolling update,API Server 内存被打到 OOM。改成”基于 LastSyncResourceVersion 的 Resync + 只在真正丢 watch 时才全量 LIST”后,重启成本下降 95%。


24.6 控制器与调度器的吞吐

万节点下,串行 reconcile 会积压。对策:

  • 调度器并行:kube-scheduler 1.19+ 的 Scheduling Framework 把 Filter/Score 做成插件,且支持多条 profile、并行打分。但根本瓶颈——“同一时刻只能 commit 一个 Pod 的绑定”——靠 Permit/Reserve 阶段 + 批量绑定(KEP-251,1.23+ 的 PodSchedulingReadiness 与批量绑定)缓解。
  • 控制器并发 worker:kube-controller-manager --concurrent-deployment-syncs=10 这类参数,把每个控制器的 reconcile worker 数调高。但注意:worker 多了,对 API Server 的 LIST/WATCH 压力也大,要配合 APF 配额。
  • 禁用无用控制器:大集群里如果不用 ReplicationController、不用 ServiceAccount token 老机制,可以 --controllers=* 里减掉,省 CPU。

⚠️ 坑:盲目加 --concurrent-*-syncs 到很大,控制器会”打爆”API Server 的写。曾有人调到 50,结果 Deployment 控制器疯狂 PATCH,etcd 写入反被自己的控制器拖垮。调并发要先看 API Server 的写 QPS 监控,两者联动调。


24.7 网络数据面:规则从 iptables 到 IPVS 到 eBPF

第 9 章讲过 Service 的 VIP 是 iptables/ipvs 规则。万节点下:

  • iptables 模式的死亡螺旋:每个 Service 在 iptables 里是一串规则链,kube-proxy 用”全量重写”方式更新。Service 上千、规则几万条时,单次更新要遍历整张表,CPU 飙到 100%、规则刷新延迟数秒,且线性查找让新连接建立变慢。
  • IPVS 模式:用哈希表做转发,查找 O(1),规则更新增量。万节点强烈建议开 --proxy-mode=ipvs。
  • eBPF(Cilium 等):直接在内核ebpf 程序里做 Service 路由和 NetworkPolicy,连 iptables/ipvs 的 netfilter 钩子都绕开,性能再上一个量级,且支持 L3-L4 之外的 L7 策略。这是”规模逼出新结构”的又一条演化线。

墨:注意一个反直觉点——iptables 模式在中小集群没事,一上规模就崩。这说明什么?

你:说明大多数设计的”够用”是有规模前提的。iptables 设计时不假设上千 Service 频繁变更。规模把隐藏的”全量重建 + 线性查找”代价放大了。

墨:对。规模是设计的试金石。K8s 没让 iptables 模式下线,而是给了 IPVS、给了 eBPF 这个”新方法”去解决老瓶颈——兼容优先、渐进替换,又是第 18 章那套演化规律。


24.8 对象爆炸的”总量治理”

除了 EndpointSlice 分片,万节点还要从”根上”减对象:

  • 节点数硬上限:官方建议单集群 ≤ 5000 节点(1.21 前),后来社区压测到 5000-15000 节点需要大量调优。超过就考虑多集群(第 23 章)——单集群不是银弹。
  • Pod 密度:每节点 Pod 数默认 110,调 --max-pods。但 Pod 多了,EndpointSlice、kube-proxy 规则、etcd 对象全跟着涨,要算总账。
  • 别滥用 ConfigMap 挂载:一个 1MB 的 ConfigMap 被 1 万个 Pod 挂载,etcd 里它一份,但每个节点内存里一份、每次 watch 都推一份。大配置考虑放对象存储、用 initContainer 拉。
  • Event 限流:--event-ttl 调短(如 1h),避免 Event 在 etcd 堆积。

24.9 一张作战图:五层调优清单

把全章汇成一张”万节点调优作战图”,从最贵到最便宜:

层瓶颈解法收益
etcd 写event 噪声、Node 心跳event 拆库、Lease主库写降 50%+
etcd 存储配额满、db 膨胀大配额、compaction+defrag、NVMe不雪崩、低延迟
API Server扇出、LIST 风暴watch cache、APF、分离优先级关键流量不被饿死
对象模型EndpointSlice 大对象EndpointSlice 分片广播面降一个量级
网络数据面iptables 全量重建IPVS / eBPF规则更新 O(1)
控制器/调度串行积压并发 worker、批量绑定reconcile 延迟降

墨:你看这张图,调优的本质是”分层降压”——每一层都只解决自己那一档的瓶颈,且不破坏声明式/控制循环/CP 这些根基。这就是”在系统设计哲学内调优”,而不是另起炉灶。

你:所以规模调优,不是堆参数,是先读懂每一层的设计假设,再用新方法把被规模放大的副产物压回去。

墨:精辟。记住一句话收尾这章——规模不会创造新问题,它只是把被你忽略的老问题,放大到你再也绕不开。


24.10 演化线小结

  • 问题:万节点下,etcd 写放大、watch 扇出、LIST 风暴、对象爆炸、串行 reconcile 这些”小集群无害”的副产物,被规模放大成致命瓶颈。
  • 设计分离:etcd 是 CP 你改不了语义 → 把”吵闹可丢”流量(event)请出主库;把”心跳”从大对象(Node)降级到小对象(Lease);用 EndpointSlice 把大端点集分片;API Server 用 watch cache 收口扇出、用 APF 保关键流量;数据面用 IPVS/eBPF 替代 iptables 全量重建。
  • 演化规律:又是”分片降写放大、兼容优先渐进替换、规模逼出结构优化”三条老规律的新例证。K8s 没有为规模重写核心,而是在每一层补一个”解决老瓶颈的新方法”,且新旧共存。

24.11 思考题

🔧 思考题 1(etcd 写):为什么说”给 etcd 加机器”救不了万节点的写入瓶颈?要从 Raft 的提交过程解释。

【参考答案】etcd 是强一致 CP 存储,每次写入要走 Raft:leader 把日志复制给所有 follower,且必须收到**多数派(quorum)**的确认才能 commit。这意味着单次的写入延迟,取决于”最慢那个 follower 的磁盘 fsync + 网络 RTT”,而不是你加多少节点。加 follower 反而让 quorum 更大、确认更慢。真正能救写入的是:减少写入量(event 拆库、Lease 降级)、用更快的盘(降 fsync 延迟)、以及减少单次写入的数据大小——这些都是”降压”,不是”加算力”。所以加机器治的是读/算力,治不了 CP 写入的固有延迟。

🔧 思考题 2(扇出):API Server 的 watch cache 是怎么把”N 客户端 × M 对象”的扇出收口的?客户端直接 watch etcd 不行吗?

【参考答案】如果不经过 API Server,N 个客户端直接 watch etcd,etcd 要维护 N 个 watch 连接、对每次变更做 N 次推送——etcd 自己先被扇出打死。K8s 的设计是:少量 API Server 副本各自 watch etcd(只 N_api 个连接),在内存里维护每个资源的有序 watch cache;海量客户端(kube-proxy、控制器)来 LIST+WATCH 时,API Server 从自己的缓存返回并基于缓存版本续接 watch。于是”对象变更→etcd”只推给少量 API Server,“对象变更→海量客户端”由 API Server 在内存里扇出。代价是 API Server 内存要装下全量缓存(万节点几个 GB),且 API Server 必须高可用——这正是用”内存 + 少量连接”换”etcd 不被扇出打死”的取舍。

🔧 思考题 3(EndpointSlice):Endpoints 对象在 1.21 后还存在吗?kube-proxy 还读它吗?为什么 K8s 不干脆删掉老 Endpoints?

【参考答案】老 Endpoints 对象在 1.21+ 仍然由 endpoint-controller 生成(为了向后兼容那些还在用 endpoints.subnets 字段的旧工具/自定义控制器)。但 kube-proxy 1.19+ 默认只消费 EndpointSlice,不再依赖老 Endpoints 做转发规则。不删老 Endpoints 是 K8s 的”兼容优先”演化纪律——生态里还有大量代码读它,强行删除会 break 一堆用户。所以 K8s 的解法是”新旧并存,新路径默认走新结构,旧结构保留但不推荐”,用时间换兼容。

🔧 思考题 4(进阶·总账):假设你接手一个 8000 节点集群,API Server P99 延迟 800ms、etcd 写入偶发 leader 切换、kube-proxy 规则更新延迟 5 秒。请你按”分层降压”思路,排出排查与调优的顺序,并说明每一刀为什么这么切。

【参考答案】顺序是”先最贵的写,再扇出,再 LIST,最后参数”:

  1. etcd 写入:先看 etcd 写 QPS 构成。若 Event 占比高 → 立刻把 /events 拆到独立 etcd 实例(24.2.1);确认 Node 心跳是否已走 Lease(1.17+ 默认走,确认没被降级);换本地 NVMe 盘;调大配额并配 compaction+轮流派 defrag。这一刀直接降主库写压力,解除 leader 切换。
  2. API Server 扇出:开大 watch cache sizes、确认 APF 开启且系统组件在高优先级(24.3)。这保住 kubelet/kube-proxy 的关键流量不被自定义控制器饿死,P99 延迟应明显回落。
  3. 对象模型:确认 EndpointSlice 已生效、老 Endpoints 不是瓶颈;若 Service 数上万,检查 kube-proxy 是否还读老 Endpoints(24.4)。
  4. 网络数据面:kube-proxy 规则更新 5 秒,典型 iptables 全量重建症状 → 切 --proxy-mode=ipvs(24.7),延迟降到毫秒级。
  5. 最后才调 --max-requests-inflight / 并发 worker 等参数,且要与前面监控联动。 为什么这个顺序:前几刀动的是”架构级副产物”(写放大、扇出、全量重建),收益最大且不可逆伤害最小;参数微调是末位,因为它治标、且容易因调错把 API Server 自己拖垮。顺序反了,参数拉满也救不了结构性瓶颈。

墨:第 24 章把”规模”这把刀亮出来了。下一章我们换个角度——万一整个控制面塌了、region 没了,你的集群怎么活?这就是灾备、跨区域与 RTO/RPO。你会发现,灾备的本质,是”把 etcd 这个单点状态的恢复,变成可以演练的工程”。

(第 24 章 完)