Kubernetes CPU limits 导致 P99 飙升?CFS 节流原理与资源模型调优实践
2026/9/4 23:32:12 网站建设 项目流程

提起 Kubernetes 里的 CPU limits,很多人的第一反应是:不给 Pod 设 CPU 上限,万一业务失控把整台节点吃满怎么办?我过去也是这么想的,而且集群里每个 Deployment 都会老老实实写上resources.limits.cpu。真正让我转变的是一次线上事故:服务 CPU 使用率平均下来不到 60%,节点也不是瓶颈,可是接口 P99 从平时的 80ms 一路涨到 800ms,重启后短暂恢复,过几个小时又复发。最后定位到根因,不是业务代码,不是数据库,而是我给容器设置的 CPU limits 触发了大量 CFS 节流(throttling)。

所以这篇文章想把经验整理清楚:CPU limits 到底做了什么、为什么会让服务变慢、什么场景真的需要它,以及不设 limits 之后集群靠什么来保护。内容适合正在维护 Kubernetes 集群的运维、SRE,以及负责服务容器化和容量规划的开发同学。

1. 先看懂 requests 和 limits:一个是“怎么分”,一个是“怎么限”

1.1 调度层面:requests 决定 Pod 能落在哪台节点

在 Kubernetes 里,resources.requestsresources.limits是两套完全不同的机制,但很多人会把它们混在一起理解。

requests首先是调度依据。你在 Pod 里声明requests.cpu: 1,kube-scheduler 找节点时,会检查节点上已经分配的 requests 总和,只有剩余可分配 CPU 大于等于 1 核,这个节点才会被选中。也就是说,requests 决定了 Pod 能不能调度上去,也决定了节点会不会超卖。

requests 另一个作用是在容器运行期映射到 cgroup 的权重。Linux cgroup v1 里对应cpu.shares,cgroup v2 里对应cpu.weight。这里的权重不是“固定给你留 1 核”,而是“节点 CPU 紧张时,大家按权重分”。比如节点上有两个 Pod,一个 request 2 核,一个 request 1 核,两者都在抢 CPU 时,理论上资源按 2:1 分配。

如果其中一个 Pod 很闲,另一个 Pod 在节点 CPU 空闲时可以把没人用的核借过来跑。也就是说,requests 不会硬性限制一个 Pod 只能用自己声称的份额。这个“借 CPU”的特性非常重要,它意味着只设置 requests 的在线业务,在突发流量时是有机会临时超出声明的。

1.2 执行层面:limits 是给 cgroup 加 CFS 配额

limits.cpu则完全不同。Kubernetes 会把 CPU limits 转换成 cgroup 的 CFS quota。以 cgroup v1 为例,核心是两个文件:

  • cpu.cfs_period_us:配额周期,默认通常是 100000 微秒,也就是 100ms。
  • cpu.cfs_quota_us:在一个周期内,这个控制组最多能使用多少 CPU 时间。

如果你给容器设置limits.cpu: 2,换算结果是 2 个核心在 100ms 内最多累积使用 200ms CPU 时间。内核会按这个周期不断检查,用完了就把该 cgroup 里的线程冻结,直到下一个周期重新分配预算。

这与很多人脑中的“给容器留 2 个核的独立空间”完全不一样。CPU limits 不是在物理核上做隔离,而是在时间账本上做“超额冻结”。

配置方式实际起作用的位置行为特点
只设置 requests调度器、cpu.shares / cpu.weight确定放置位置和争抢权重,不休眠惩罚
设置 limitscpu.cfs_quota_us / cpu.max周期内 CPU 时间硬上限,超后直接节流
requests 和 limits 都设置两者都生效调度按 requests,运行期有硬顶

还有一个容易踩的坑:在 Kubernetes 里,如果你只写了limits没写requests,requests 会被默认成和 limits 一样。也就是说,你以为自己“只限了 2 核没承诺 2 核”,实际上调度、权重都按照 2 核算进去了。这会导致节点看起来被占掉很多资源,但真实利用率很低。

1.3 关键结论:limits 不等于预留能力,而是“超时会暂停”

现在可以把结论先放在这里:

  • requests 是一种“软保证”,让调度器知道你大概需要多少,并在 CPU 争抢时按比例分配。
  • limits 是一种“硬封顶”,超过配额后线程会被挂起,直到下一个周期。

很多人在设计资源模型时,把 requests 看成“启动预留”,把 limits 看成“运行时保护”。但从内核执行机制看,limits 更像是在 cgroup 层面实现了一个“用完了就先停机”的开关。这个开关在 CPU 密集型离线任务里问题不大,但对在线延迟敏感服务可能是灾难。

2. 为什么 CPU 没用满,服务却明显变慢

2.1 CFS 配额按周期结算,突发流量最容易触发节流

CPU 节流最反直觉的一点是:并不需要平均 CPU 使用率超过 limits 才会被节流

CFS 带宽控制是按周期结算的。假设容器 limit 是 1 核,那么在一个 100ms 周期里,最多消费 100ms CPU 时间。如果应用有多个线程,或者在某一个周期里请求突然增多,线程可以在很短的真实时间内把整个周期的预算消耗完。预算消耗完之后,容器里所有想要运行的任务都会被暂停,直到下一个 100ms 周期重新开始。

举个例子:容器限制 1 核,应用同时来了 4 个请求,4 个线程分布在 4 个不同 CPU 核心上运行。如果每个线程跑了 30ms,4 个线程加起来就是 120ms CPU 时间,但 100ms 配额一共只有 100ms,超过之后所有线程立刻被冻结,最快也要等下一个周期才能恢复。

从分钟级监控看,CPU 使用率可能只有 50%,因为其他周期很空闲。但在这 100ms 的微观窗口里,线程已经被打断了。对接口来说,表现为一次高延迟;对消息处理来说,表现为一批消息延迟。

这就是为什么“监控图上 CPU 不高”和“服务不该变慢”之间没有必然关系。你看到的曲线是平滑后的平均值,而节流发生在毫秒级的时间片里。

2.2 多线程应用会把“平均限额”快速耗尽

单线程应用相对不容易被节流,因为它在一个周期内最多也就消耗一个核的时间。真正危险的是多线程应用,尤其是线程池、异步框架、并发请求处理非常多的服务。

Java 服务是一个典型场景。应用配置了核心线程池,平时同一时刻只有少量请求,CPU 占用不高。一旦流量抖动,几十个线程同时处理任务,这些线程分散在不同物理核上,每一毫秒真实时间里可能累计消耗几十毫秒 CPU。CFS 只看这个 cgroup 的累计消耗,不会看你“平均负载是不是很低”。于是预算很快见底,线程被强制休眠。

等下一个周期恢复后,线程刚开始处理,新的请求又来,几个周期内预算又被打满。最终表现为:CPU 使用率远低于 limit,但线程执行被切得支离破碎,耗时自然涨上去。

流量越有突发性、线程越多、连接池越大,这个问题越明显。相反,一个严格控制并发度、任何时候只有固定数量线程在跑 CPU 的应用,反而不容易出现这种隐蔽节流。

2.3 Java、Go、Node 等运行时更容易看到抖动

除了应用自身的多线程,语言运行时本身也会产生短促 CPU 尖峰。

Java 应用有 JIT 编译、GC、锁竞争、线程池调度。一次 Full GC 可能让 CPU 短暂飙升,如果刚好撞上 CFS 配额不足,GC 停顿会被进一步放大。Node.js 虽然主线程偏单线程,但事件循环、异步 IO、Worker Thread 并发跑起来时,同样可能在短窗口内消耗大量 CPU。Go 的 goroutine 调度对 CPU 数很敏感,runtime 会按可使用的 CPU 数来调整并行度,但运行时内部仍然可能因为某个时间段内的调度压力产生尖峰。

这些运行时层面的短促消耗,不是业务代码里能直接看到的。你看到的现象就是“同样的并发量,之前能扛住,设置完 CPU limits 后开始大量超时”。

3. 先确认你的 Pod 到底有没有被节流

3.1 看指标:cfs_throttled 比 cfs_periods

要验证是不是被 CPU limits 坑了,不能只凭感觉。最直接的指标是 cgroup 里的 CFS 节流统计。

在 Prometheus 里,如果使用 kubelet 内置的 cAdvisor 指标,会有这样的指标:

  • container_cpu_cfs_periods_total:CFS 周期总次数。
  • container_cpu_cfs_throttled_periods_total:发生节流的周期次数。
  • container_cpu_cfs_throttled_seconds_total:累计被节流的秒数。

日常可以算这个比例:

rate(container_cpu_cfs_throttled_periods_total{container!="POD",container!=""}[5m]) / rate(container_cpu_cfs_periods_total{container!="POD",container!=""}[5m])

这个值可以理解为“最近 5 分钟里有节流的周期占比”。低于 5% 通常可以接受;如果超过 20%,节流已经是一个非常明确的嫌疑对象;如果到了 50% 以上,在线服务大概率会出现明显的 P99 抖动。

如果集群使用 cgroup v2,也可以通过container_cpu_cfs_throttled_periods_total继续查,cAdvisor 会汇总到同样的指标命名上。

3.2 从应用侧看:P99 上升但 CPU 不高,多半是节流

单看集群指标还不够,要结合应用侧表现一起判断。我发现一套比较有效的观察顺序:

  1. 先看应用监控里的 P99、P95、超时率是否突然上升。
  2. 再看容器 CPU 使用率,此时往往不高,甚至远低于 requests。
  3. 再查 CFS throttled,如果比例高,基本可以锁定是 limits 导致。
  4. 顺手看一下节点整体 CPU,如果节点很空闲,说明不是资源不够,而是容器自身的“天花板”提前把线程压住了。

这个组合特征非常典型:应用不是真的缺资源,但被一个微时间片层面的配额卡住了。

有条件的还可以在 Pod 里直接读取 cgroup 信息验证。cgroup v1 环境:

cat /sys/fs/cgroup/cpu/cpu.stat

输出里会给出nr_periodsnr_throttledthrottled_time三个字段。throttled_time是纳秒,如果它持续增长,说明节流正在发生。

3.3 看现场:线程调度和响应时间更能说明问题

如果指标层面已经确认有节流,再看线程现场会很明显。用top -H -p <pid>jstack观察 Java 线程,会看到线程大量处于RUNNABLE状态,但整体吞吐很低。这其实是线程本来想跑,内核却不给 CPU 预算,于是任务一直排着队。

我见过最典型的情况是:容器限了 4 核,但 Pod 里线程池有 16 个线程,并发一上来,线程分布到 16 个核上,实际上每秒能拿到的时间却只有“4 核 × 运行时间”。线程池越大,每个线程分到的 CPU 时间越碎,等待越多。

这个阶段不要先去调业务线程池大小。先去掉 CPU limits 验证,如果 P99 明显回落,再去考虑线程模型才是正确的排查顺序。

4. 哪些场景是真的必须设置 CPU limits

先说明白:我不赞同“所有 Pod 一律不许设置 CPU limits”这种一刀切建议。生产环境不是只有在线接口服务,也不是只有你一个人在用集群。CPU limits 在某些场景下仍然有存在价值。

4.1 多租户和强隔离场景需要硬边界

如果你的集群被多个团队共用,或者你正在向外部团队提供容器平台能力,那“某一个 Pod 长期占用空闲 CPU”可能引发其他团队投诉。

比如节点上跑了一个资源模型比较激进的团队应用,其他 Pod 相对空闲。按 cpu.shares 的分配机制,应用之间会互相借用空闲 CPU。占用方可能突然把整台节点压满,导致同节点上其他延迟敏感服务在抢 CPU 时受到明显干扰。

这种场景下,给高噪声风险的工作负载设置 CPU limits,至少可以保证它永远不会吃超过预设上限。虽然 CFS 节流机制有副作用,但相比“完全无上限导致租户互相伤害”,强隔离的收益更大。

4.2 CPU 密集型离线任务和批处理任务可以接受节流

离线任务、批处理、数据同步、模型推理等负载对单次请求延迟不敏感,更在意整体吞吐和资源可控性。

这类任务通常有明确的 CPU 消耗上限,设置 limits 反而合适:

  • 任务本身是 CPU 密集的,不存在“突发请求导致节流”的应用语义。
  • throttle 后任务只是变慢,不会造成用户可感知的超时。
  • 如果同一个节点还混跑在线服务,离线任务的 CPU limits 可以防止它把节点 CPU 抢空。

做法上,我建议把这类工作负载放到独立的 ResourceQuota 或独立命名空间里管理,避免“在线服务不许设 limits、离线任务必须设 limits”两种策略混在一起难以追踪。

4.3 平台侧必须用 ResourceQuota 和 LimitRange 做容量边界

很多公司不是由业务自己决定怎么设 limits,而是平台在 K8s 控制面通过 ResourceQuota、LimitRange 做了统一约束。

ResourceQuota 可以限制命名空间里所有 Pod 的 requests 和 limits 总量。比如这个团队最多只能申请 32 核 requests、64 核 limits。这保证了集群的整体容量有边界,不会因为某个人声明了超大 requests 就把整个集群的资源占光。

如果平台有强制要求每个 Deployment 必须出现 limits,那也不是完全没救。你可以在合理的基线评估后,把 limits 设置成一个远高于 requests 的“保险值”,而不是当成精确的运行时约束。这样既满足了平台规范,又不会让节流在日常流量下轻易发生。

4.4 对延迟不敏感但必须保护整机安全的任务

有些内部工具、监控采集器、日志采集器本身不要求低延迟,但对稳定性有要求。如果代码里有死循环或异常重试,会直接把节点 CPU 打满。

这种情况下设置一个比较宽松的 CPU limits,比如 requests 100m、limits 2 核,可以防住最极端的失控情况。同时因为这类任务不会出现毫秒级突发流量,被 CFS 节流影响业务的可能性很小。

5. 不设 limits 后,集群靠什么来保护

既然 CPU limits 副作用明显,那去掉之后集群不会失控吗?我的答案分两层:第一,不要在没有任何容量体系和监控体系的情况下裸奔式去 limits;第二,Kubernetes 本身提供了比硬切断更合适的机制。

5.1 用 requests 做准入和调度,保证资源不超卖

去掉 CPU limits 之后,requests 依然是调度器和 kubelet 做资源核算的依据。Pod 申请多少 requests,调度时就会扣掉多少可分配资源。

也就是说,只要你把 requests 写得真实,节点不会出现“100 个 Pod 都说自己要 1 核,实际上节点一共 8 核”的极端超卖情况。requests 的语义虽然没有硬性隔离,但在调度层面已经限制了数量。

这里的关键是:requests 必须接近真实使用量,不能为了省资源随意写低。我见过一个比较普遍的错误是 requests 写 100m,但服务正常运行就要 4 核,结果一个节点塞了几十个这样的 Pod,CPU 一紧张谁都跑不动。

正确做法是让业务提供长期运行中 P75 或 P90 的 CPU 使用率,再乘一个 1.2 到 1.5 的缓冲系数,改成 requests 的基线。这不是精确公式,但比拍脑袋强很多。

5.2 用 QoS 分级处理节点压力下的驱逐顺序

去掉 CPU limits 后,Pod 的 QoS 类型可能会变化。这里要弄清楚:

  • 只有 requests 和 limits 都设置且相等时,Pod 才是 Guaranteed。
  • 只设置 requests、不设置 limits,Pod 大概率是 Burstable。
  • requests 和 limits 都没设置,Pod 是 BestEffort。

节点发生内存压力时,kubelet 会先驱逐 BestEffort,再驱逐 Burstable 中超出 requests 的 Pod,最后才考虑 Guaranteed。所以如果你把 CPU limits 去掉了,但内存层面仍然设置了合理 limits,那么 QoS 能不能保住,要看内存的 requests 和 limits 是否相等。

我不建议为了拿到 Guaranteed QoS 而强行让 CPU requests 等于 limits。真正重要的是内存有保护,CPU 让调度器按权重分。这个选择在绝大多数在线服务里都合理。

5.3 用 HPA 处理负载伸缩,而不是靠单 Pod 硬顶

很多设置 CPU limits 的出发点,是想“单 Pod 被限制住,别影响节点”。这其实是靠单点硬扛的思路。Kubernetes 设计上更鼓励横向伸缩。

去掉 CPU limits 后,HPA 的意义会更大。HPA 可以基于 CPU 利用率自动扩缩副本,例如:

apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: web-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70

HPA 计算 CPU 利用率时,依据的是 Pod 的 requests,而不是实际可用的物理核。因此 requests 必须贴近真实负载。请求上来时,HPA 会扩容多个副本分担压力,而不是让单个 Pod 在 cgroup 配额里被反复冻结。

5.4 用 LimitRange 和 ResourceQuota 约束规格边界

如果担心团队里有人完全不写 requests,平台侧可以借助 LimitRange 兜底。

LimitRange 可以给没有声明 resources 的容器设置默认 requests 和 limits。例如:

apiVersion: v1 kind: LimitRange metadata: name: resource-profile spec: limits: - type: Container defaultRequest: cpu: 200m memory: 256Mi default: cpu: "4" memory: 1Gi

这里给容器默认设置了 CPU limits 为 4 核。这是平台兜底逻辑,不等于你要在每一个业务 Deployment 里手动写死 limits。真正的容量控制还可以放在 ResourceQuota 上:

apiVersion: v1 kind: ResourceQuota metadata: name: namespace-quota spec: hard: requests.cpu: "32" limits.cpu: "128" requests.memory: 64Gi limits.memory: 128Gi

ResourceQuota 限制的是命名空间整体资源量。即使单个 Pod 不设 CPU limits,它也不能突破整个命名空间的总请求量上限。平台想做精细化,通常是“ResourceQuota 管总量 + LimitRange 管默认值 + 业务自己管 requests”,而不是把所有压力都压在单个容器的 limits 上。

5.5 需要强 CPU 绑定时,依赖 CPU 管理策略而不是 limits

如果你真正的诉求是“这个 Pod 必须独占某些物理核心”,那么 CFS quota 不是合适的工具。Kubernetes 提供了静态 CPU 管理策略,可以让满足条件的 Guaranteed Pod 独占 CPU。

但这要求 Pod 的 CPU requests 和 limits 是相等的,而且必须是整数。所以这类高延迟敏感服务反而需要设置 CPU limits。它和你现在“为了防失控而设置 limits”不是一个目的。先想清楚自己是要“独占 CPU”还是“防止失控”。需要独占核心的服务,走 CPU manager 的专用节点;普通在线服务,更依赖 requests 和 HPA。

6. 实在绕不开 limits 时,怎么设才不离谱

有些团队因为历史原因、平台规范或者安全要求,CPU limits 无法完全去掉。这时候可以把损失降到最低。

6.1 limit 一定要明显高于 requests

最忌讳的写法是requests.cpu: 1limits.cpu: 1。这样 Pod 的 CPU 上限几乎等于正常使用基线,任何突发都会触发节流。

比较稳妥的做法是先看监控里的 CPU 使用分位数。如果服务日常 P95 是 1.2 核,峰值能到 2 核,requests 可以写 1.2 到 1.5 核,limits 至少写到 3 到 4 核。limists 的作用只保留“防止失控吃满整机”,而不是精确限制日常运行。

limits 相对 requests 的倍数需要根据业务形态判断:

  • 在线接口服务:2 到 4 倍比较合理,甚至更高。
  • 消息消费者:1.5 到 3 倍。
  • 离线批处理任务:1.2 到 2 倍,因为它本来就在持续吃 CPU。
  • 未知负载类型:先在测试环境观察两周,不要直接上生产。

这个倍数没有标准答案。原则是:预留的冗余足够覆盖突发,而不只是覆盖平均值

6.2 重点监测节流率和突发耗时

设置了 limits 之后,不要只看 CPU 使用率,要把节流指标纳入日常监控。

我建议至少配置两条规则:

- record: namespace_cpu_throttle_ratio expr: | sum by (namespace, pod, container) ( rate(container_cpu_cfs_throttled_periods_total[5m]) ) / sum by (namespace, pod, container) ( rate(container_cpu_cfs_periods_total[5m]) )

然后用这条记录规则配置告警,阈值可以先定 20%。如果连续 10 分钟超过这个阈值,说明当前 limits 已经影响到业务运行了。

真正做容量评估时,要同时看三组数字:

  1. Pod 实际 CPU 使用率。
  2. CFS throttled 比例。
  3. 应用 P99 和超时率。

三组放在一起看,才能判断“是不是 limits 太少”还是“应用并发模型不合理”。

6.3 降低周期影响,先把应用自身并发控制做好

有些团队为了不设过大的 limits,选择限制业务并发度。这个方向是对的,但要做在应用层,不要在 K8s 层用 cgroup 配额硬切。

在应用代码里,我们可以用信号量、连接池、最大并发数来控制同时执行的任务数量。比如某个服务本来可以用 16 个线程处理请求,但你已经算过单 Pod 最多稳定提供 4 核 CPU,那就把线程池调到 8 个以下。这样 CPU 消耗自然收敛,不再依赖 limits 去“踩刹车”。

如果应用无法快速改造,设置 limits 前也要考虑给 Pod 的spec.containers[].resources.limits.cpu设置一个冗余空间。为了一时安全把 limit 压到和 requests 一样,不是保护,是制造故障。

6.4 按 Pod 和按 namespace 双重规划容量

我见过很多服务单看资源使用不高,但整个 namespace 的 requests 总量已经远超节点能力。去掉 CPU limits 后,调度器只看 requests,一旦某个 namespace 的 requests 总量没有控制住,节点超卖率会变得不可控。

所以就算单个业务不设 limits,也要通过 ResourceQuota 限制 namespace 维度的总量。不能只做 Pod 层面的细粒度限制,而完全不管团队整体申请了多少资源。容量规划要分两层:单个 Pod 能涨多高,整个 Namespace 能涨多高。

7. 落地建议:先怎么改,后续怎么验证

如果在你的集群里还不能立刻全量去掉 CPU limits,我建议采用渐进式变更,而不是某一天突然把线上所有 Deployment 的 limits 都删掉。

7.1 从单条服务开始试点,不要全集群一刀切

第一步,挑一个没有强依赖、可以让流量按百分比灰度切换的服务。先去掉它的limits.cpu,但保留requests.cpu。YAML 里大概长这样:

resources: requests: cpu: 1 memory: 1Gi # limits: # cpu: "2" # memory: 2Gi

注意:当你移除 CPU limits 但保留内存 limits 时,Pod 的 QoS 通常会变成 Burstable。服务如果一直有合理的内存 limits,并且内存 requests 设得也够,这在生产上通常是可以接受的。

第二步,对比变更前和变更后的节流指标。如果以前的 cfs_throttle_ratio 长期在 20% 以上,去掉后应该明显降到接近 0。如果去掉后没有变化,说明问题不在 limits,需要继续往下排查应用代码或节点层。

第三步,观察一周,包括 P99、错误率、Pod 重启次数、节点 CPU 稳态。只有这些没有劣化,才扩大试点范围。

7.2 观察周期、指标和告警配置不要只看平均值

试点阶段不要只盯 CPU 的平均使用率。要用短窗口去观察:

  • 1 分钟 CPU 峰值。
  • CFS throttled 比例变化。
  • 容器线程调度是否有大量 runnable 等待。
  • 应用自身队列长度和超时分布。

至少要积累三天以上包含流量高峰的数据。如果只在低峰期测试,突发流量导致的节流可能根本不会被触发。很多人改完配置发现“没问题”,是因为低峰期根本没有机会产生短时 CPU 尖峰。

7.3 排查顺序与常见误区

最后整理一套我自己比较常用的排查顺序,遇到“CPU 不高但服务很慢”时按这个来:

  1. 先确认 Pod 是否在一直重启。如果是健康检查失败导致频繁杀掉重启,不要先怀疑 CPU limits。
  2. 再看 CFS throttled 指标。占比高,优先怀疑 limits。
  3. 看节点整体 CPU 和内存压力。节点都满了,去掉 Pod limits 也没用,要扩容或分散负载。
  4. 看应用层日志、GC、线程池、数据库慢查询。这些也都会造成 CPU 不高但接口慢。
  5. 最后看 requests 是否设置合理。requests 太高会导致调度不上去,requests 太低会导致超卖严重。

常见的误区有三个:

  • 误区一:CPU limits 能防 OOM。实际上 OOM 主要由 memory limits 控制,CPU limits 和内存不直接相关。
  • 误区二:CPU limits 等于预留 CPU。实际上它只是时间预算的硬顶,而且副作用明显。
  • 误区三:去掉 limits 后节点肯定会被打满。实际上只要 requests 真实,再配合 HPA、ResourceQuota 和合理的调度策略,节点是可管理的。

回到开头那个线上事故,最后我做的动作其实很朴素:把核心在线服务的limits.cpu去掉,保留合理 requests,同时给集群加了基于 cfs_throttled 的监控。几小时后 P99 回到基线,服务再也没有出现“资源看着够、响应莫名慢”的诡异现象。

如果你所在的团队还处在“所有 Pod 必须设置 limits”的阶段,我建议先不要说服所有人。先选一个服务做对照实验,把节流率、P99、CPU 峰值做成报告,用数据推动资源模型调整会更有效。Kubernetes 的资源管理从来不是“设得越严越好”,而是要让调度、权重、伸缩各自干自己擅长的事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询