第 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。问题:
- 一个 Service 的 Endpoints 对象可能几十 KB(上千端点)。
- 任一端点变 → 整个 Endpoints 对象重写 → 推给所有 watch 它的 kube-proxy。
- 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,最后参数”:
- etcd 写入:先看 etcd 写 QPS 构成。若 Event 占比高 → 立刻把
/events拆到独立 etcd 实例(24.2.1);确认 Node 心跳是否已走 Lease(1.17+ 默认走,确认没被降级);换本地 NVMe 盘;调大配额并配 compaction+轮流派 defrag。这一刀直接降主库写压力,解除 leader 切换。 - API Server 扇出:开大 watch cache sizes、确认 APF 开启且系统组件在高优先级(24.3)。这保住 kubelet/kube-proxy 的关键流量不被自定义控制器饿死,P99 延迟应明显回落。
- 对象模型:确认 EndpointSlice 已生效、老 Endpoints 不是瓶颈;若 Service 数上万,检查 kube-proxy 是否还读老 Endpoints(24.4)。
- 网络数据面:kube-proxy 规则更新 5 秒,典型 iptables 全量重建症状 → 切
--proxy-mode=ipvs(24.7),延迟降到毫秒级。 - 最后才调
--max-requests-inflight/ 并发 worker 等参数,且要与前面监控联动。 为什么这个顺序:前几刀动的是”架构级副产物”(写放大、扇出、全量重建),收益最大且不可逆伤害最小;参数微调是末位,因为它治标、且容易因调错把 API Server 自己拖垮。顺序反了,参数拉满也救不了结构性瓶颈。
墨:第 24 章把”规模”这把刀亮出来了。下一章我们换个角度——万一整个控制面塌了、region 没了,你的集群怎么活?这就是灾备、跨区域与 RTO/RPO。你会发现,灾备的本质,是”把 etcd 这个单点状态的恢复,变成可以演练的工程”。
(第 24 章 完)