大规模集群:万节点集群优化经验
一句话定位:集群从 1000 到 10000 节点,不是"线性扩容",而是"处处撞墙"------本文把生产里真实踩过的瓶颈、参数、架构改造讲透,让你少走两年弯路。
写在前面
带过一个从 800 节点涨到 12000 节点的集群,过程中几乎把 K8s 每一层都改了一遍。1000 节点是"小集群",3000 节点开始"出问题",5000 节点"卡天花板",10000 节点"必须分片或拆集群"。这一篇把我踩过的所有坑整理出来,从 API Server → etcd → kube-proxy → 调度器 → 多集群架构,给一份"万节点集群容量规划表"和"瓶颈排查清单"。
K8s 官方说 1.30 单集群支持 5000 节点、15 万 Pod,但这是"理论上限",生产实践里要留 30% 余量,实际能扛的稳定水位在 3500-4500 节点。再大就要考虑分片调度器或多集群架构。
核心问题
集群规模上去了,性能怎么不崩?
瓶颈不是一处,是连锁的:
节点多 → Pod 多 → API Server QPS 高 → etcd 写入慢
→ watch 流量大 → API Server 内存爆
→ kube-proxy iptables 规则多 → 网络慢
→ 调度器打分慢 → Pod 启动慢
→ Service 数量多 → Endpoint 切换抖动
→ Controller Manager 队列堆积 → 资源同步延迟
每一段都要专门优化,缺一段就崩。
一、原理剖析
1.1 单集群规模上限分析
K8s 官方 SLA:5000 节点、15 万 Pod、30 万容器、单集群 ≤ 5 万 Service。
#mermaid-svg-FlAQp5alfzwDsaBK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FlAQp5alfzwDsaBK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FlAQp5alfzwDsaBK .error-icon{fill:#552222;}#mermaid-svg-FlAQp5alfzwDsaBK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FlAQp5alfzwDsaBK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FlAQp5alfzwDsaBK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FlAQp5alfzwDsaBK .marker.cross{stroke:#333333;}#mermaid-svg-FlAQp5alfzwDsaBK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FlAQp5alfzwDsaBK p{margin:0;}#mermaid-svg-FlAQp5alfzwDsaBK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FlAQp5alfzwDsaBK .cluster-label text{fill:#333;}#mermaid-svg-FlAQp5alfzwDsaBK .cluster-label span{color:#333;}#mermaid-svg-FlAQp5alfzwDsaBK .cluster-label span p{background-color:transparent;}#mermaid-svg-FlAQp5alfzwDsaBK .label text,#mermaid-svg-FlAQp5alfzwDsaBK span{fill:#333;color:#333;}#mermaid-svg-FlAQp5alfzwDsaBK .node rect,#mermaid-svg-FlAQp5alfzwDsaBK .node circle,#mermaid-svg-FlAQp5alfzwDsaBK .node ellipse,#mermaid-svg-FlAQp5alfzwDsaBK .node polygon,#mermaid-svg-FlAQp5alfzwDsaBK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FlAQp5alfzwDsaBK .rough-node .label text,#mermaid-svg-FlAQp5alfzwDsaBK .node .label text,#mermaid-svg-FlAQp5alfzwDsaBK .image-shape .label,#mermaid-svg-FlAQp5alfzwDsaBK .icon-shape .label{text-anchor:middle;}#mermaid-svg-FlAQp5alfzwDsaBK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FlAQp5alfzwDsaBK .rough-node .label,#mermaid-svg-FlAQp5alfzwDsaBK .node .label,#mermaid-svg-FlAQp5alfzwDsaBK .image-shape .label,#mermaid-svg-FlAQp5alfzwDsaBK .icon-shape .label{text-align:center;}#mermaid-svg-FlAQp5alfzwDsaBK .node.clickable{cursor:pointer;}#mermaid-svg-FlAQp5alfzwDsaBK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FlAQp5alfzwDsaBK .arrowheadPath{fill:#333333;}#mermaid-svg-FlAQp5alfzwDsaBK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FlAQp5alfzwDsaBK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FlAQp5alfzwDsaBK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FlAQp5alfzwDsaBK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FlAQp5alfzwDsaBK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FlAQp5alfzwDsaBK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FlAQp5alfzwDsaBK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FlAQp5alfzwDsaBK .cluster text{fill:#333;}#mermaid-svg-FlAQp5alfzwDsaBK .cluster span{color:#333;}#mermaid-svg-FlAQp5alfzwDsaBK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FlAQp5alfzwDsaBK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FlAQp5alfzwDsaBK rect.text{fill:none;stroke-width:0;}#mermaid-svg-FlAQp5alfzwDsaBK .icon-shape,#mermaid-svg-FlAQp5alfzwDsaBK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FlAQp5alfzwDsaBK .icon-shape p,#mermaid-svg-FlAQp5alfzwDsaBK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FlAQp5alfzwDsaBK .icon-shape .label rect,#mermaid-svg-FlAQp5alfzwDsaBK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FlAQp5alfzwDsaBK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FlAQp5alfzwDsaBK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FlAQp5alfzwDsaBK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 单集群瓶颈
API Server
max-requests-inflight 限制
etcd
存储 + fsync 延迟
kube-proxy
iptables 规则爆炸
Controller Manager
资源 watch 流量
Scheduler
扫描节点数
kubelet
与 APIServer 心跳流量
CoreDNS
Service 解析 QPS
5000 节点意味着 5 万 Pod、15 万容器(每 Pod 3 容器),各组件压力:
| 组件 | 1000 节点 | 5000 节点 | 瓶颈 |
|---|---|---|---|
| API Server QPS | 100 | 500+ | max-requests-inflight |
| etcd db 大小 | 500MB | 2.5GB | quota-backend-bytes |
| etcd fsync 延迟 | 5ms | 15ms+ | 磁盘 IO |
| kube-proxy iptables 规则 | 1 万 | 5 万+ | O(N) 匹配 |
| EndpointSlice 数 | 1000 | 5000+ | watch 流量 |
| Pod 启动延迟 P99 | 3s | 15s+ | 调度器 |
1.2 API Server 优化
#mermaid-svg-mxRfHnzPGMWxqa37{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mxRfHnzPGMWxqa37 .error-icon{fill:#552222;}#mermaid-svg-mxRfHnzPGMWxqa37 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mxRfHnzPGMWxqa37 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mxRfHnzPGMWxqa37 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mxRfHnzPGMWxqa37 .marker.cross{stroke:#333333;}#mermaid-svg-mxRfHnzPGMWxqa37 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mxRfHnzPGMWxqa37 p{margin:0;}#mermaid-svg-mxRfHnzPGMWxqa37 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 .cluster-label text{fill:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 .cluster-label span{color:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 .cluster-label span p{background-color:transparent;}#mermaid-svg-mxRfHnzPGMWxqa37 .label text,#mermaid-svg-mxRfHnzPGMWxqa37 span{fill:#333;color:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 .node rect,#mermaid-svg-mxRfHnzPGMWxqa37 .node circle,#mermaid-svg-mxRfHnzPGMWxqa37 .node ellipse,#mermaid-svg-mxRfHnzPGMWxqa37 .node polygon,#mermaid-svg-mxRfHnzPGMWxqa37 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mxRfHnzPGMWxqa37 .rough-node .label text,#mermaid-svg-mxRfHnzPGMWxqa37 .node .label text,#mermaid-svg-mxRfHnzPGMWxqa37 .image-shape .label,#mermaid-svg-mxRfHnzPGMWxqa37 .icon-shape .label{text-anchor:middle;}#mermaid-svg-mxRfHnzPGMWxqa37 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mxRfHnzPGMWxqa37 .rough-node .label,#mermaid-svg-mxRfHnzPGMWxqa37 .node .label,#mermaid-svg-mxRfHnzPGMWxqa37 .image-shape .label,#mermaid-svg-mxRfHnzPGMWxqa37 .icon-shape .label{text-align:center;}#mermaid-svg-mxRfHnzPGMWxqa37 .node.clickable{cursor:pointer;}#mermaid-svg-mxRfHnzPGMWxqa37 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mxRfHnzPGMWxqa37 .arrowheadPath{fill:#333333;}#mermaid-svg-mxRfHnzPGMWxqa37 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mxRfHnzPGMWxqa37 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mxRfHnzPGMWxqa37 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mxRfHnzPGMWxqa37 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mxRfHnzPGMWxqa37 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mxRfHnzPGMWxqa37 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mxRfHnzPGMWxqa37 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mxRfHnzPGMWxqa37 .cluster text{fill:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 .cluster span{color:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mxRfHnzPGMWxqa37 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mxRfHnzPGMWxqa37 rect.text{fill:none;stroke-width:0;}#mermaid-svg-mxRfHnzPGMWxqa37 .icon-shape,#mermaid-svg-mxRfHnzPGMWxqa37 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mxRfHnzPGMWxqa37 .icon-shape p,#mermaid-svg-mxRfHnzPGMWxqa37 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mxRfHnzPGMWxqa37 .icon-shape .label rect,#mermaid-svg-mxRfHnzPGMWxqa37 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mxRfHnzPGMWxqa37 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mxRfHnzPGMWxqa37 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mxRfHnzPGMWxqa37 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} mutating
readonly
Client 请求
AuthN/AuthZ
Admission
Inflight 限制
mutating max 200
readonly max 400
etcd 写入
etcd 读/watch cache
关键参数:
--max-requests-inflight:mutating 请求并发上限,默认 400--max-mutating-requests-inflight:默认 200--default-watch-cache-size:每个资源的 watch cache 大小,默认 100--watch-cache-sizes:按资源单独设置,如pod#5000,configmap#1000
watch cache 是关键优化点。每个 client(每个 kubelet、每个 controller)对 Pod 资源都会建立一个 watch,5000 kubelet 同时 watch Pod,API Server 内存爆。
1.3 etcd 分区与调优
etcd 单实例在 5000 节点下,典型 db 大小 2-4GB,fsync 延迟 P99 > 20ms。
#mermaid-svg-NfwiiZdEWridvP3B{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NfwiiZdEWridvP3B .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NfwiiZdEWridvP3B .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NfwiiZdEWridvP3B .error-icon{fill:#552222;}#mermaid-svg-NfwiiZdEWridvP3B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NfwiiZdEWridvP3B .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NfwiiZdEWridvP3B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NfwiiZdEWridvP3B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NfwiiZdEWridvP3B .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NfwiiZdEWridvP3B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NfwiiZdEWridvP3B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NfwiiZdEWridvP3B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NfwiiZdEWridvP3B .marker.cross{stroke:#333333;}#mermaid-svg-NfwiiZdEWridvP3B svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NfwiiZdEWridvP3B p{margin:0;}#mermaid-svg-NfwiiZdEWridvP3B .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NfwiiZdEWridvP3B .cluster-label text{fill:#333;}#mermaid-svg-NfwiiZdEWridvP3B .cluster-label span{color:#333;}#mermaid-svg-NfwiiZdEWridvP3B .cluster-label span p{background-color:transparent;}#mermaid-svg-NfwiiZdEWridvP3B .label text,#mermaid-svg-NfwiiZdEWridvP3B span{fill:#333;color:#333;}#mermaid-svg-NfwiiZdEWridvP3B .node rect,#mermaid-svg-NfwiiZdEWridvP3B .node circle,#mermaid-svg-NfwiiZdEWridvP3B .node ellipse,#mermaid-svg-NfwiiZdEWridvP3B .node polygon,#mermaid-svg-NfwiiZdEWridvP3B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NfwiiZdEWridvP3B .rough-node .label text,#mermaid-svg-NfwiiZdEWridvP3B .node .label text,#mermaid-svg-NfwiiZdEWridvP3B .image-shape .label,#mermaid-svg-NfwiiZdEWridvP3B .icon-shape .label{text-anchor:middle;}#mermaid-svg-NfwiiZdEWridvP3B .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NfwiiZdEWridvP3B .rough-node .label,#mermaid-svg-NfwiiZdEWridvP3B .node .label,#mermaid-svg-NfwiiZdEWridvP3B .image-shape .label,#mermaid-svg-NfwiiZdEWridvP3B .icon-shape .label{text-align:center;}#mermaid-svg-NfwiiZdEWridvP3B .node.clickable{cursor:pointer;}#mermaid-svg-NfwiiZdEWridvP3B .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NfwiiZdEWridvP3B .arrowheadPath{fill:#333333;}#mermaid-svg-NfwiiZdEWridvP3B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NfwiiZdEWridvP3B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NfwiiZdEWridvP3B .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NfwiiZdEWridvP3B .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NfwiiZdEWridvP3B .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NfwiiZdEWridvP3B .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NfwiiZdEWridvP3B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NfwiiZdEWridvP3B .cluster text{fill:#333;}#mermaid-svg-NfwiiZdEWridvP3B .cluster span{color:#333;}#mermaid-svg-NfwiiZdEWridvP3B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NfwiiZdEWridvP3B .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NfwiiZdEWridvP3B rect.text{fill:none;stroke-width:0;}#mermaid-svg-NfwiiZdEWridvP3B .icon-shape,#mermaid-svg-NfwiiZdEWridvP3B .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NfwiiZdEWridvP3B .icon-shape p,#mermaid-svg-NfwiiZdEWridvP3B .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NfwiiZdEWridvP3B .icon-shape .label rect,#mermaid-svg-NfwiiZdEWridvP3B .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NfwiiZdEWridvP3B .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NfwiiZdEWridvP3B .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NfwiiZdEWridvP3B :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} etcd 写入
WAL 日志
fsync 同步
Backend DB
BoltDB
定期 Snapshot
压缩历史
瓶颈 1
WAL fsync 延迟
瓶颈 2
DB 压缩不及时
瓶颈 3
大 Range 查询
扫全表
三个优化方向:
- WAL 独立盘:NVMe SSD,fsync P99 < 5ms
- 压缩 + defrag :
auto-compaction-retention=1h,每周 defrag 一次 - 避免大 Range 查询:Controller 改用 List + ResourceVersion watch,不用 List without limit
1.4 kube-proxy ipvs 大规模优化
iptables 在 5000 节点 + 1 万 Service 时,规则数 50 万+,kube-proxy 同步耗时 30s+,Pod 访问 Service 延迟 50ms+。
ipvs 模式下:
- 规则查找复杂度 O(1)(hash 表)
- 同步时间 < 5s
- 但
ipvs -Ln输出本身在大规模下也很慢
ipvs 的瓶颈在 EndpointSlice 同步,5000 节点 + 1 万 Service,每次 Endpoint 变更都触发 ipvs 规则更新,需要把 --min-sync-period 调到 1s 减少抖动。
#mermaid-svg-B6wPtJ9eO5cvCR5V{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-B6wPtJ9eO5cvCR5V .error-icon{fill:#552222;}#mermaid-svg-B6wPtJ9eO5cvCR5V .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-B6wPtJ9eO5cvCR5V .marker{fill:#333333;stroke:#333333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .marker.cross{stroke:#333333;}#mermaid-svg-B6wPtJ9eO5cvCR5V svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-B6wPtJ9eO5cvCR5V p{margin:0;}#mermaid-svg-B6wPtJ9eO5cvCR5V .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .cluster-label text{fill:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .cluster-label span{color:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .cluster-label span p{background-color:transparent;}#mermaid-svg-B6wPtJ9eO5cvCR5V .label text,#mermaid-svg-B6wPtJ9eO5cvCR5V span{fill:#333;color:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .node rect,#mermaid-svg-B6wPtJ9eO5cvCR5V .node circle,#mermaid-svg-B6wPtJ9eO5cvCR5V .node ellipse,#mermaid-svg-B6wPtJ9eO5cvCR5V .node polygon,#mermaid-svg-B6wPtJ9eO5cvCR5V .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .rough-node .label text,#mermaid-svg-B6wPtJ9eO5cvCR5V .node .label text,#mermaid-svg-B6wPtJ9eO5cvCR5V .image-shape .label,#mermaid-svg-B6wPtJ9eO5cvCR5V .icon-shape .label{text-anchor:middle;}#mermaid-svg-B6wPtJ9eO5cvCR5V .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .rough-node .label,#mermaid-svg-B6wPtJ9eO5cvCR5V .node .label,#mermaid-svg-B6wPtJ9eO5cvCR5V .image-shape .label,#mermaid-svg-B6wPtJ9eO5cvCR5V .icon-shape .label{text-align:center;}#mermaid-svg-B6wPtJ9eO5cvCR5V .node.clickable{cursor:pointer;}#mermaid-svg-B6wPtJ9eO5cvCR5V .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .arrowheadPath{fill:#333333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B6wPtJ9eO5cvCR5V .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-B6wPtJ9eO5cvCR5V .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B6wPtJ9eO5cvCR5V .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-B6wPtJ9eO5cvCR5V .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .cluster text{fill:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V .cluster span{color:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-B6wPtJ9eO5cvCR5V .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-B6wPtJ9eO5cvCR5V rect.text{fill:none;stroke-width:0;}#mermaid-svg-B6wPtJ9eO5cvCR5V .icon-shape,#mermaid-svg-B6wPtJ9eO5cvCR5V .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B6wPtJ9eO5cvCR5V .icon-shape p,#mermaid-svg-B6wPtJ9eO5cvCR5V .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-B6wPtJ9eO5cvCR5V .icon-shape .label rect,#mermaid-svg-B6wPtJ9eO5cvCR5V .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B6wPtJ9eO5cvCR5V .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-B6wPtJ9eO5cvCR5V .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-B6wPtJ9eO5cvCR5V :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1s
0s
Endpoint 变更
API Server watch
kube-proxy 收到事件
min-sync-period
批量同步 ipvs 规则
立即同步
大规模抖动
1.5 大规模 NetworkPolicy 性能
NetworkPolicy 在 iptables 模式下,规则数 = O(Pod × Policy),5000 节点 + 1000 Policy 时,iptables 规则上百万,严重拖垮网络。
#mermaid-svg-4g292vAKz0iZAMHM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4g292vAKz0iZAMHM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4g292vAKz0iZAMHM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4g292vAKz0iZAMHM .error-icon{fill:#552222;}#mermaid-svg-4g292vAKz0iZAMHM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4g292vAKz0iZAMHM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4g292vAKz0iZAMHM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4g292vAKz0iZAMHM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4g292vAKz0iZAMHM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4g292vAKz0iZAMHM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4g292vAKz0iZAMHM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4g292vAKz0iZAMHM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4g292vAKz0iZAMHM .marker.cross{stroke:#333333;}#mermaid-svg-4g292vAKz0iZAMHM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4g292vAKz0iZAMHM p{margin:0;}#mermaid-svg-4g292vAKz0iZAMHM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4g292vAKz0iZAMHM .cluster-label text{fill:#333;}#mermaid-svg-4g292vAKz0iZAMHM .cluster-label span{color:#333;}#mermaid-svg-4g292vAKz0iZAMHM .cluster-label span p{background-color:transparent;}#mermaid-svg-4g292vAKz0iZAMHM .label text,#mermaid-svg-4g292vAKz0iZAMHM span{fill:#333;color:#333;}#mermaid-svg-4g292vAKz0iZAMHM .node rect,#mermaid-svg-4g292vAKz0iZAMHM .node circle,#mermaid-svg-4g292vAKz0iZAMHM .node ellipse,#mermaid-svg-4g292vAKz0iZAMHM .node polygon,#mermaid-svg-4g292vAKz0iZAMHM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4g292vAKz0iZAMHM .rough-node .label text,#mermaid-svg-4g292vAKz0iZAMHM .node .label text,#mermaid-svg-4g292vAKz0iZAMHM .image-shape .label,#mermaid-svg-4g292vAKz0iZAMHM .icon-shape .label{text-anchor:middle;}#mermaid-svg-4g292vAKz0iZAMHM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4g292vAKz0iZAMHM .rough-node .label,#mermaid-svg-4g292vAKz0iZAMHM .node .label,#mermaid-svg-4g292vAKz0iZAMHM .image-shape .label,#mermaid-svg-4g292vAKz0iZAMHM .icon-shape .label{text-align:center;}#mermaid-svg-4g292vAKz0iZAMHM .node.clickable{cursor:pointer;}#mermaid-svg-4g292vAKz0iZAMHM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4g292vAKz0iZAMHM .arrowheadPath{fill:#333333;}#mermaid-svg-4g292vAKz0iZAMHM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4g292vAKz0iZAMHM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4g292vAKz0iZAMHM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4g292vAKz0iZAMHM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4g292vAKz0iZAMHM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4g292vAKz0iZAMHM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4g292vAKz0iZAMHM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4g292vAKz0iZAMHM .cluster text{fill:#333;}#mermaid-svg-4g292vAKz0iZAMHM .cluster span{color:#333;}#mermaid-svg-4g292vAKz0iZAMHM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4g292vAKz0iZAMHM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4g292vAKz0iZAMHM rect.text{fill:none;stroke-width:0;}#mermaid-svg-4g292vAKz0iZAMHM .icon-shape,#mermaid-svg-4g292vAKz0iZAMHM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4g292vAKz0iZAMHM .icon-shape p,#mermaid-svg-4g292vAKz0iZAMHM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4g292vAKz0iZAMHM .icon-shape .label rect,#mermaid-svg-4g292vAKz0iZAMHM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4g292vAKz0iZAMHM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4g292vAKz0iZAMHM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4g292vAKz0iZAMHM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Calico iptables
Calico eBPF
Cilium eBPF
kube-router
Pod 间流量
CNI 实现
顺序匹配规则
N 条 Policy
eBPF 程序
O1 查找
同上 + 更优
iptables 但简化
大规模集群推荐 Cilium eBPF,完全绕过 iptables,NetworkPolicy 在 eBPF 层执行,O(1) 查找。
1.6 Service 数量瓶颈
每个 Service 都对应:
- 一条 iptables/ipvs 规则(kube-proxy)
- 一组 EndpointSlice(默认 100 Endpoint/slice)
- 一条 CoreDNS 解析记录
5000 节点集群,Service 1 万+,CoreDNS QPS 上 10 万,单个 CoreDNS Pod 处理能力 5 万 QPS,需要至少 3 副本 + NodeLocalDNSCache。
1.7 大规模调度器优化
默认调度器在 5000 节点下,单次调度延迟 P99 > 1s,Pod 启动延迟显著。
优化方向:
percentageOfNodesToScore=30(扫描 30% 节点)NodeResourcesFit用MostAllocated(集中调度,减少碎片)- 多调度器分片(coscheduling / volcano)
- 调度器缓存调大
1.8 多集群分流架构
5000 节点是单集群天花板,10000+ 必须多集群:
#mermaid-svg-s99bgsmhXI9xKBi4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-s99bgsmhXI9xKBi4 .error-icon{fill:#552222;}#mermaid-svg-s99bgsmhXI9xKBi4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-s99bgsmhXI9xKBi4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-s99bgsmhXI9xKBi4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-s99bgsmhXI9xKBi4 .marker.cross{stroke:#333333;}#mermaid-svg-s99bgsmhXI9xKBi4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-s99bgsmhXI9xKBi4 p{margin:0;}#mermaid-svg-s99bgsmhXI9xKBi4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 .cluster-label text{fill:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 .cluster-label span{color:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 .cluster-label span p{background-color:transparent;}#mermaid-svg-s99bgsmhXI9xKBi4 .label text,#mermaid-svg-s99bgsmhXI9xKBi4 span{fill:#333;color:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 .node rect,#mermaid-svg-s99bgsmhXI9xKBi4 .node circle,#mermaid-svg-s99bgsmhXI9xKBi4 .node ellipse,#mermaid-svg-s99bgsmhXI9xKBi4 .node polygon,#mermaid-svg-s99bgsmhXI9xKBi4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-s99bgsmhXI9xKBi4 .rough-node .label text,#mermaid-svg-s99bgsmhXI9xKBi4 .node .label text,#mermaid-svg-s99bgsmhXI9xKBi4 .image-shape .label,#mermaid-svg-s99bgsmhXI9xKBi4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-s99bgsmhXI9xKBi4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-s99bgsmhXI9xKBi4 .rough-node .label,#mermaid-svg-s99bgsmhXI9xKBi4 .node .label,#mermaid-svg-s99bgsmhXI9xKBi4 .image-shape .label,#mermaid-svg-s99bgsmhXI9xKBi4 .icon-shape .label{text-align:center;}#mermaid-svg-s99bgsmhXI9xKBi4 .node.clickable{cursor:pointer;}#mermaid-svg-s99bgsmhXI9xKBi4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-s99bgsmhXI9xKBi4 .arrowheadPath{fill:#333333;}#mermaid-svg-s99bgsmhXI9xKBi4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-s99bgsmhXI9xKBi4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-s99bgsmhXI9xKBi4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-s99bgsmhXI9xKBi4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-s99bgsmhXI9xKBi4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-s99bgsmhXI9xKBi4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-s99bgsmhXI9xKBi4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-s99bgsmhXI9xKBi4 .cluster text{fill:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 .cluster span{color:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-s99bgsmhXI9xKBi4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-s99bgsmhXI9xKBi4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-s99bgsmhXI9xKBi4 .icon-shape,#mermaid-svg-s99bgsmhXI9xKBi4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-s99bgsmhXI9xKBi4 .icon-shape p,#mermaid-svg-s99bgsmhXI9xKBi4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-s99bgsmhXI9xKBi4 .icon-shape .label rect,#mermaid-svg-s99bgsmhXI9xKBi4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-s99bgsmhXI9xKBi4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-s99bgsmhXI9xKBi4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-s99bgsmhXI9xKBi4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 全局流量入口
Ingress/Gateway
Cluster A
3000 节点
Cluster B
3000 节点
Cluster C
3000 节点
Cluster D
3000 节点
KubeFed / Karmada
联邦控制面
全局服务发现
Mesh DNS
主流方案:
- Karmada:华为开源,主流多集群编排
- KubeFed v2:CNCF,发展缓慢
- Service Mesh 多集群(Istio / Linkerd Multi-cluster):服务级分流
- ClusterAPI:多集群生命周期管理
二、实战操作
2.1 API Server 大规模配置
yaml
# /etc/kubernetes/manifests/kube-apiserver.yaml 关键参数
spec:
containers:
- command:
- kube-apiserver
# 并发与限流
- --max-requests-inflight=1000 # 默认 400,调大
- --max-mutating-requests-inflight=400 # 默认 200
- --min-request-timeout=1800 # 请求超时 30min
# watch cache(关键!)
- --default-watch-cache-size=1000 # 默认 100,调大
- --watch-cache-sizes=pod#10000,node#5000,secret#5000,configmap#5000,endpoints#10000,services#5000
# etcd
- --etcd-servers=https://etcd1:2379,https://etcd2:2379,https://etcd3:2379
- --etcd-servers-overrides=/events#https://etcd-events1:2379 # events 分离!
# APF(API Priority and Fairness,1.20+ 必开)
- --enable-priority-and-fairness=true
# 日志
- --logtostderr=true
- --v=2
# 性能
- --default-not-ready-toleration-seconds=300
- --default-unreachable-toleration-seconds=300
# gc
- --event-ttl=1h # 默认 1h,大集群可缩短
resources:
requests:
cpu: "8"
memory: "32Gi"
limits:
cpu: "16"
memory: "64Gi"
APF 配置(PriorityLevel + FlowSchema,大规模集群关键):
yaml
# 关键业务高优先级(不会被限流挤掉)
apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
kind: PriorityLevelConfiguration
metadata:
name: critical-workload
spec:
type: Limited
limited:
nominalConcurrencyShares: 1000 # 高配额
limitResponse:
type: Queue
queuing:
queues: 128
handSize: 8
---
apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
kind: FlowSchema
metadata:
name: critical-controllers
spec:
priorityLevelConfiguration:
name: critical-workload
distinguisherMethod:
type: ByUser
rules:
- subjects:
- kind: ServiceAccount
namespace: kube-system
name: controller-manager
resourceRules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
2.2 etcd 分区(Events 单独存)
大规模集群必须把 events 分到独立 etcd,否则 events 写入会拖垮主 etcd。
bash
# 部署独立 etcd 集群(3 节点)
# etcd-events.yaml
cat > /etc/kubernetes/manifests/etcd-events.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: etcd-events
namespace: kube-system
spec:
hostNetwork: true
containers:
- name: etcd
image: registry.k8s.io/etcd:3.5.12
command:
- etcd
- --name=etcd-events-1
- --data-dir=/var/lib/etcd-events
- --wal-dir=/var/lib/etcd-events/wal
- --snapshot-count=10000
- --quota-backend-bytes=8589934592
- --auto-compaction-retention=1h
- --listen-client-urls=https://0.0.0.0:2381
- --advertise-client-urls=https://NODE_IP:2381
- --listen-peer-urls=https://0.0.0.0:2382
- --initial-advertise-peer-urls=https://NODE_IP:2382
- --initial-cluster=etcd-events-1=https://NODE1:2382,etcd-events-2=https://NODE2:2382,etcd-events-3=https://NODE3:2382
- --initial-cluster-token=etcd-events-cluster
- --initial-cluster-state=new
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
- --client-cert-auth=true
- --peer-client-cert-auth=true
volumeMounts:
- mountPath: /var/lib/etcd-events
name: etcd-events-data
volumes:
- name: etcd-events-data
hostPath:
path: /var/lib/etcd-events
type: DirectoryOrCreate
EOF
kube-apiserver 加 --etcd-servers-overrides:
yaml
- --etcd-servers-overrides=/events#https://etcd-events1:2381,https://etcd-events2:2381,https://etcd-events3:2381
2.3 kube-proxy ipvs 大规模优化
yaml
# kube-proxy configmap
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
scheduler: "lc" # 最少连接,大规模优于 rr
strictARP: true
minSyncPeriod: "1s" # 关键!避免抖动
syncPeriod: "30s"
tcpTimeout: "0s" # 不设置超时,让应用自己管
tcpFinTimeout: "0s"
udpTimeout: "30s"
excludeCIDRs:
- "10.0.0.0/8" # 内网 CIDR 不走 ipvs
conntrack:
maxPerCore: 0 # 0 = 用节点 nf_conntrack_max
min: 1048576
tcpCloseWaitTimeout: "30s"
tcpEstablishedTimeout: "86400s"
configSyncPeriod: "15m"
iptables:
masqueradeAll: false
masqueradeBit: 14
minSyncPeriod: "1s"
syncPeriod: "30s"
验证 ipvs 模式下大规模性能:
bash
# 看规则数
kubectl -n kube-system exec ds/kube-proxy -- ipvsadm -Ln | wc -l
# 看同步延迟(关键指标)
# Prometheus: sync_proxy_rules_iptables_equivalent_last_duration_seconds
kubectl -n kube-system exec ds/kube-proxy -- cat /var/log/kube-proxy.log | grep "syncing rules"
# 看单个 Pod 访问 Service 延迟
kubectl run benchmark --rm -it --image=registry.k8s.io/perf-tests/benchmark:latest -- \
/bin/sh -c "for i in \$(seq 1 100); do \
time curl -s -o /dev/null http://order-service.prod.svc:8080/health; \
done"
2.4 NetworkPolicy 大规模:Cilium eBPF
bash
# 1. 卸载原有 CNI(警告:会断网,生产需在维护窗口)
# 2. 部署 Cilium
helm install cilium cilium/cilium --version 1.15.6 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost=API_SERVER_IP \
--set k8sServicePort=6443 \
--set ipv4.enabled=true \
--set ipv6.enabled=false \
--set enableIPv4EgressGateway=true \
--set ipv4NativeRoutingCIDR=10.0.0.0/8 \
--set bgpControlPlane.enabled=false \
--set l7Proxy=false \
--set hubble.enabled=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distrib,icmp}" \
--set prometheus.enabled=true \
--set operator.prometheus.enabled=true \
--set encryption.enabled=true \
--set encryption.type=ipsec \
--set encryption.nodeEncryption=true
# 3. 大规模优化参数
cat > cilium-values-large-scale.yaml <<'EOF'
k8sClientRateLimit:
qps: 100
burst: 200
k8sApiServerBurst: 100
k8sApiServerQPS: 50
# 大规模下 bpf map 要调大
bpf:
masquerade: true
lbAlgorithm: "maglev" # 比 rr 更稳定
ct:
tcpMax: 536870912 # 5亿,默认 512万
anyMax: 268435456
nat:
max: 536870912
neigh:
alloqHost: true
lbMapNum: 6
policyMapMax: 16384
sessionAffinityMapMax: 16384
# cilium-agent 资源
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2
memory: 2Gi
# 大规模下 bpf masquerade 优于 iptables masquerade
enableBPFMasquerade: true
enableIPv4Masquerade: true
# 监控
extraArgs:
- "--enable-policy=default"
- "--policy-queue-size=512"
- "--k8s-events-queue-size=512"
EOF
helm upgrade cilium cilium/cilium -n kube-system -f cilium-values-large-scale.yaml
2.5 CoreDNS 优化 + NodeLocalDNSCache
大规模集群 CoreDNS 是绝对瓶颈,必须上 NodeLocalDNSCache。
yaml
# CoreDNS configmap 优化
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
# 关键:大规模用 forward 而不是 proxy,效率高
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
# prometheus 监控
prometheus :9153
# forward 上游 DNS
forward . /etc/resolv.conf {
max_concurrent 1000
prefer_udp
}
# 缓存(大规模调大)
cache 30 {
success 4096 60 30
denial 4096 60 30
prefetch 5 30s 20%
}
# 限流(防止个别 Pod 把 DNS 拖垮)
ratelimit {
rate 1000
burst 2000
ok 0
}
reload 10s
loadbalance round_robin
log . {
class denial error
}
}
部署 NodeLocalDNSCache(每个节点一个 Pod,DNS 请求本地缓存):
bash
# 下载 manifest
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
# 修改本地 IP 为 169.254.20.10,转发到 CoreDNS
# 部署
kubectl apply -f nodelocaldns.yaml
# 所有 Pod 的 /etc/resolv.conf 自动指向 169.254.20.10
2.6 调度器优化
yaml
# kube-scheduler config
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: /etc/kubernetes/scheduler.conf
# 大规模调大 burst
burst: 200
qps: 100
percentageOfNodesToScore: 30
profiles:
- schedulerName: default-scheduler
plugins:
filter:
enabled:
- name: NodeUnschedulable
- name: NodeName
- name: TaintToleration
- name: NodeAffinity
- name: NodeResourcesFit
- name: VolumeRestrictions
- name: EBSLimits
- name: GCEPDLimits
- name: AzureDiskLimits
- name: VolumeBinding
- name: VolumeZone
- name: PodTopologySpread
score:
enabled:
- name: NodeResourcesFit
weight: 5
- name: InterPodAffinity
weight: 2
- name: PodTopologySpread
weight: 2
- name: NodeAffinity
weight: 1
preScore:
enabled:
- name: InterPodAffinity
- name: PodTopologySpread
config:
nodeResourcesFit:
scoringStrategy:
type: MostAllocated # 集中调度减少碎片
podTopologySpread:
defaultConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
2.7 大规模集群容量规划表
1000-3000 节点集群参考配置:
| 组件 | 配置 | 备注 |
|---|---|---|
| Master 节点 | 3 × 16C64G NVMe | 高可用 |
| etcd | 3 × 4C16G NVMe 独立 | 主 etcd |
| etcd-events | 3 × 2C8G NVMe 独立 | events 分离 |
| API Server | 8C32Gi | max-inflight 1000 |
| Scheduler | 2C4Gi | percentage 50 |
| Controller Manager | 2C8Gi | 并发 50 |
| CoreDNS | 3 × 500m 512Mi | + NodeLocalDNSCache |
| Prometheus | 8C32Gi + 500GB | TSDB 15 天 |
| 节点 | 16C64G | Pod 密度 80 |
5000 节点集群参考配置:
| 组件 | 配置 | 备注 |
|---|---|---|
| Master 节点 | 5 × 32C128G | 多 Master |
| etcd | 5 × 8C32G NVMe | 5 副本 |
| etcd-events | 3 × 4C16G | events 独立 |
| API Server | 16C64Gi | max-inflight 1500 |
| CoreDNS | 5 × 1C1Gi | + NodeLocalDNSCache 强制 |
| 节点 | 32C128G | Pod 密度 100 |
2.8 多集群分流架构(Karmada)
bash
# 部署 Karmada 控制面
helm install karmada karmada/karmada \
--namespace karmada-system \
--create-namespace \
--set apiServer.replicaCount=3 \
--set etcd.replicaCount=3 \
--set apiServer.serviceType=LoadBalancer
# 注册子集群
kubectl karmada join cluster-a --cluster-kubeconfig=karmada.kubeconfig \
--cluster-context=karmada-apiserver \
--member-cluster-kubeconfig=cluster-a.kubeconfig
# 部署 PropagationPolicy(应用如何分发到子集群)
cat > propagation.yaml <<'EOF'
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: order-service-policy
namespace: prod
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: order-service
- apiVersion: v1
kind: Service
name: order-service
placement:
clusterAffinity:
clusterNames:
- cluster-a
- cluster-b
- cluster-c
replicaScheduling:
replicaSchedulingType: Divided
replicaDivisionPreference: Weighted
weightPreference:
staticWeightList:
- targetCluster:
clusterNames: [cluster-a]
weight: 1
- targetCluster:
clusterNames: [cluster-b]
weight: 1
- targetCluster:
clusterNames: [cluster-c]
weight: 1
EOF
2.9 瓶颈排查清单
bash
#!/bin/bash
# bottleneck-check.sh
echo "===== 集群瓶颈排查 ====="
# 1. API Server 延迟
echo -e "\n## API Server 延迟 P99(目标 < 1s)"
curl -s http://localhost:8080/metrics | grep apiserver_request_duration_seconds | \
grep -E "quantile=\"0.99\"" | sort
# 2. etcd 延迟
echo -e "\n## etcd fsync 延迟 P99(目标 < 10ms)"
ETCDCTL_API=3 etcdctl endpoint status -w table
# 3. 调度延迟
echo -e "\n## 调度延迟 P99(目标 < 500ms)"
curl -s http://localhost:10259/metrics | grep scheduler_scheduling_algorithm_duration_seconds | \
grep -E "quantile=\"0.99\""
# 4. kube-proxy 同步延迟
echo -e "\n## kube-proxy 同步延迟(目标 < 5s)"
curl -s http://localhost:10249/metrics | grep sync_proxy_rules_iptables_equivalent_last_duration_seconds
# 5. CoreDNS QPS
echo -e "\n## CoreDNS QPS(每副本 < 5000)"
kubectl -n kube-system exec deploy/coredns -- cat /tmp/coredns.log | grep "queries" | wc -l
# 6. Controller Manager 队列堆积
echo -e "\n## Controller Manager 队列"
curl -s http://localhost:10252/metrics | grep workqueue_depth | sort -k2 -rn | head -5
# 7. 节点心跳延迟
echo -e "\n## 节点心跳延迟(目标 < 60s)"
kubectl get nodes -o json | jq -r '
.items[] |
"\(.metadata.name): \(.status.conditions[] | select(.type == "Ready") | .lastHeartbeatTime)"
'
# 8. Pod 启动延迟 P99(过去 1 小时)
echo -e "\n## Pod 启动延迟 P99(目标 < 5s)"
# 通过 Prometheus 查询 kube_pod_container_state_started
三、踩坑与排查
坑 1:5000 节点后 API Server 偶发 OOM
现象:API Server Pod 内存从 32GB 涨到 64GB,频繁重启。
定位:
bash
kubectl -n kube-system top pod kube-apiserver-xxx
# 内存接近 64GB limit
kubectl -n kube-system exec kube-apiserver-xxx -- sh -c "ls /proc/1/fd | wc -l"
# 文件描述符爆,几十万
原因:每个 kubelet 都对 Pod 建立 watch,5000 kubelet × 5 watch = 2.5 万 watch 连接,每个连接占用 cache。
解决:
yaml
- --default-watch-cache-size=2000
- --watch-cache-sizes=pod#20000,node#10000,secret#5000,configmap#5000,endpoints#10000,services#5000
- --max-requests-inflight=1500
- --max-mutating-requests-inflight=500
resources:
limits:
memory: "96Gi" # 调大
同时减少 Controller Manager 的 watch 并发,改 List + watch with ResourceVersion。
坑 2:etcd 写入延迟抖动到 100ms
现象 :apiserver 日志报 etcdserver: request timed out,kubectl get 偶发卡 10s+。
定位:
bash
# 看 etcd fsync 延迟
etcdctl endpoint status -w table
# 看磁盘 IO
iostat -xz 1 | grep -E "nvme0n1|sda"
# await > 50ms
原因:etcd 数据盘和容器镜像盘共用,镜像 pull 时 IO 抖动。
解决:
- etcd 独立 NVMe SSD
- WAL 独立盘
--snapshot-count=10000--auto-compaction-retention=1h- 定期 defrag(每周)
bash
# defrag 脚本(非 leader 节点先 defrag)
ETCDCTL_API=3 etcdctl --endpoints=etcd1 defrag
ETCDCTL_API=3 etcdctl --endpoints=etcd2 defrag
ETCDCTL_API=3 etcdctl --endpoints=etcd3 defrag # leader 最后
坑 3:kube-proxy 同步耗时 30s
现象 :大规模集群下,Pod 访问 Service 偶发 502,kube-proxy 日志报 syncing rules took 30s。
定位:
bash
kubectl -n kube-system exec ds/kube-proxy -- ipvsadm -Ln | wc -l
# 几十万行,规模爆炸
# 看同步耗时
kubectl -n kube-system exec ds/kube-proxy -- cat /var/log/kube-proxy.log | grep "syncing"
原因:iptables 模式下规则数随 Service×Pod 线性增长。
解决 :切 ipvs 模式 + min-sync-period=1s。如果还不行,迁 Cilium eBPF 完全绕过 kube-proxy。
坑 4:CoreDNS 拖垮整个集群
现象 :集群偶发所有 Service 解析失败,Pod 报 no such host。
定位:
bash
kubectl -n kube-system top pods -l k8s-app=kube-dns
# CoreDNS CPU 100%
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100 | grep "too many"
# "too many open files" 或 "rate limit"
原因:单 CoreDNS Pod 处理 5 万 QPS 是上限,大规模集群 10 万+ QPS 把它打爆。
解决:
yaml
# 1. 扩容到 5 副本
spec:
replicas: 5
# 2. 加 NodeLocalDNSCache(每个节点一个本地缓存 Pod)
# 3. CoreDNS config 加 ratelimit
# 4. 监控 CoreDNS QPS,告警阈值 40000/副本
坑 5:Scheduler 卡死,Pod Pending 1 小时
现象 :某次扩容 1000 个 Pod,全部 Pending 1 小时,kubectl describe pod 显示 Scheduling disabled。
定位:
bash
kubectl -n kube-system logs kube-scheduler-xxx | tail -50
# "Unable to schedule, no nodes available" 但实际有节点
# 调度器 metrics
curl http://localhost:10259/metrics | grep scheduler_scheduling_algorithm_duration_seconds
原因:调度器全量扫描所有节点,5000 节点 × 1000 Pod = 500 万次打分。
解决:
percentageOfNodesToScore=30- 调度器加资源
- 启用调度器分片(coscheduling)
坑 6:大规模 NetworkPolicy 网络延迟 100ms+
现象:开启 NetworkPolicy 后,Pod 间通信延迟从 1ms 涨到 100ms。
定位:
bash
iptables -L | wc -l
# 几百万行规则
解决:迁 Cilium eBPF,NetworkPolicy 在 eBPF 层执行,延迟 < 1ms。
四、最佳实践
容量规划:
- 单集群 ≤ 5000 节点(生产稳定水位 3000-4000)
- 10000+ 节点用多集群,推荐 Karmada 联邦
- Master 至少 3 节点,etcd 独立 NVMe
- 节点规格统一,16C64G 或 32C128G
- Pod 密度 50-100/节点
API Server:
--max-requests-inflight=1000-1500--default-watch-cache-size调大--watch-cache-sizes按资源精细配置- 开启 APF(Priority and Fairness)
- events 走独立 etcd(
--etcd-servers-overrides) - 资源至少 8C32Gi,5000 节点 16C64Gi
etcd:
- 独立 NVMe SSD,WAL 独立盘
quota-backend-bytes=8589934592(8GB)snapshot-count=10000auto-compaction-retention=1h- 每周 defrag 一次
- 监控
etcd_disk_wal_fsync_duration_secondsP99 < 10ms - events 独立 etcd 集群
kube-proxy:
- 节点数 > 500 必须切 ipvs
- 节点数 > 2000 强烈建议 Cilium eBPF
- ipvs
scheduler=lc,min-sync-period=1s - 监控同步延迟 P99 < 5s
NetworkPolicy:
- 大规模必须 eBPF(Cilium / Calico eBPF)
- 避免 iptables 模式
- Cilium
bpf.ct.max调大到 5 亿 - 用
maglev算法替代rr
CoreDNS:
- 强制部署 NodeLocalDNSCache
- CoreDNS 副本数 = 节点数 / 1000,至少 3 个
cache 30+ratelimit 1000- 监控 QPS,告警阈值 40000/副本
调度器:
percentageOfNodesToScore=30(大规模)NodeResourcesFit用MostAllocated- 关键业务用
PriorityClass - 启用
PodTopologySpread跨 AZ 分散
监控告警:
- Prometheus 持续采集所有组件 P99 延迟
- API Server P99 < 1s
- etcd fsync P99 < 10ms
- Scheduler P99 < 500ms
- Pod 启动 P99 < 5s
- 瓶颈排查脚本每天跑
五、小结
万节点集群优化是"系统工程",不是"调一个参数":
- 架构层面:events 分离 etcd、APF 限流、多 Master、Cilium eBPF
- 参数层面:watch cache、max-inflight、ipvs min-sync、CoreDNS ratelimit
- 监控层面:Prometheus 持续采集,瓶颈排查脚本每周跑
- 演进层面:5000 是单集群上限,10000+ 必须多集群联邦
最后给一句话:不要追求单集群无限扩容,3000-5000 节点是甜蜜区,超出就拆集群。多集群的复杂度是可控的,单集群撞天花板的复杂度是不可控的。
思考题
- 单集群 5000 节点和 5 × 1000 节点集群,运维成本和性能哪个更优?什么场景该选哪个?
- APF 中
PriorityLevel的nominalConcurrencyShares=1000和=10在大规模集群里差别有多大?怎么评估? - Cilium eBPF 替换 kube-proxy 后,Service 的流量路径有哪些变化?为什么延迟会降?
- 多集群联邦(Karmada)在故障切换时,如何保证业务连续性?需要哪些前置条件?
延伸阅读
- Kubernetes 官方规模指南: https://kubernetes.io/docs/setup/best-practices/cluster-large/
- etcd 调优: https://etcd.io/docs/v3.5/tuning/
- Cilium 大规模部署: https://docs.cilium.io/en/stable/operations/performance/scaling/
- kube-proxy ipvs 模式: https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/
- Karmada 官方: https://karmada.io/docs/core-concepts/concepts/
- APF 文档: https://kubernetes.io/docs/concepts/cluster-administration/flow-control/
- 调度器优化: https://kubernetes.io/docs/reference/scheduling/config/
- cluster-loader2 压测: https://github.com/kubernetes/perf-tests/tree/master/clusterloader2
- 阿里云万节点实践: https://developer.aliyun.com/article/780155