K8s Pod怎么配置Requests和Limits才合理
摘要:# K8s里配CPU内存,别总当“差不多先生” 我前两天刚帮一个朋友看他们线上的K8s集群,好家伙,一溜Pod的Requests和Limits要么是空的,要么就瞎写。有个微服务明明吃内存跟喝水似的,Limits就给1个G,结果一天能被OOM Kill(内…
K8s里配CPU内存,别总当“差不多先生”
我前两天刚帮一个朋友看他们线上的K8s集群,好家伙,一溜Pod的Requests和Limits要么是空的,要么就瞎写。有个微服务明明吃内存跟喝水似的,Limits就给1个G,结果一天能被OOM Kill(内存溢出被杀死)七八回。运维兄弟天天忙着重启,都快成条件反射了。
这种场景你应该不陌生吧?很多团队刚上K8s,觉得容器编排自动化了,资源配额这种“小事”随便填填就行。结果呢,不是资源浪费严重,就是服务动不动崩给你看。
说白了,Requests和Limits这俩参数,就是你跟K8s集群签的“资源合同”。Requests是你要保证的“底薪”,Kubernetes调度器靠它来给你找合适的节点(Node);Limits是你的“封顶绩效”,容器用超了就得被“管教”(限流或杀死)。
今天咱就捞点干的,聊聊这合同怎么签才不吃亏。
先搞明白,这俩参数到底管啥用?
咱们打个接地气的比方。你把集群想象成一个合租房,每个Node就是一个房间,Pod就是住进来的租客。
- Requests(请求值):相当于你租床铺。你跟房东(调度器)说:“我至少要一张床的空间。”房东答应了,就会在某个房间给你预留出这张床。这部分资源是给你“保底”的,系统会保证给你,其他Pod抢不走。 如果所有房间连一张空床都没了,那新Pod就得排队等着(处于Pending状态)。
- Limits(限制值):相当于你房间的电表跳闸阈值。你虽然租了张床,但你不能把空调、冰箱、电磁炉全开着还抱怨电费高。Limits就是那个“电闸”,CPU用超了就被“限流”(Throttling),变得卡顿;内存用超了,对不起,直接“拉闸”(OOM Kill),把你这个Pod干掉重启。
很多人的第一个误区就来了:把这俩值设成一样的,不就省事了?
理论上可以,但实际很坑。你想想,你租个床铺,非得按五星级酒店套房的用电标准给你装个闸,这不是浪费吗?对于CPU这种“可压缩”资源,你设了Limit,它真用的时候就可能被限流,导致服务延迟增高,你还不好排查。所以,通常建议Requests和Limits设成不同的值,中间那点差额,就是给你应对突发流量、正常业务波动的“弹性空间”。
怎么配才算“合理”?我的野路子三步法
别去看那些公式了,我分享一个我自己常用的、从实战里摸出来的步骤。
第一步:先当个“监控侦探”,摸清家底
你都不知道你服务平时吃几碗干饭,拍脑袋配资源就是瞎搞。
- 看历史数据:打开你的监控系统(Prometheus + Grafana 是标配吧?),找到这个Pod过去7天、甚至30天的CPU/内存使用率曲线。别只看平均值,重点看峰值(Peak)和常态(比如P95/P99)。
- 抓典型场景:看看工作日和周末的区别,看看大促活动时的表现。内存尤其要看“常驻集大小”(RSS),这才是它实际占用的物理内存。
我见过一个服务,平时CPU就用个0.1核,但每到整点同步数据时,会飙到2核。如果你只按0.5核去设Limit,整点任务肯定被卡成慢动作。
第二步:Requests怎么定?—— 按“常态”再加点保险
Requests是保底资源,设得太低,节点上Pod塞得太满,一有风吹草动大家互相挤占;设得太高,资源利用率低,浪费钱。
- CPU Requests:我一般会参考P95/P99的使用量,而不是平均值。比如,你监控看到P99的CPU使用是0.5核,那Requests可以设为
0.5或0.6。给一点余量,防止偶尔的小波动导致节点负载过高。 - 内存 Requests:这个要更谨慎。内存不足可是直接杀进程的。我会看工作负载的常驻内存基线,然后上浮20%-30%。比如基线是512MiB,我会设到
600Mi或650Mi。
有个大实话得说: 对于线上核心服务,在资源不是极度紧张的情况下,我倾向于把Requests设得稍微“富裕”一点。省那点资源钱,真比不上服务不稳带来的损失。当然,这是个人偏见哈。
第三步:Limits怎么定?—— 给“天花板”,但别太低
Limits是天花板,目的是防止一个Pod发疯拖垮整个节点。
- CPU Limits:这是最需要艺术感的。如果你设了Limit,K8s就会通过CFS(完全公平调度器)来限流。我的经验是:
- 对于延迟敏感型服务(如API网关、用户请求入口),可以考虑不设CPU Limit(
cpu: “”),或者设一个很高的值(比如Requests的4-5倍),优先保障响应速度。缺点是你得信任这个服务不会出Bug狂吃CPU。 - 对于计算型、批处理型服务,可以设Limit,比如是Requests的2-3倍。让它有突发处理能力,又不至于失控。
- 对于延迟敏感型服务(如API网关、用户请求入口),可以考虑不设CPU Limit(
- 内存 Limits:这个必须设,而且一定要比Requests高。否则一启动就可能触发OOM。通常设成Requests的1.5-2倍。比如Requests是
1Gi,Limits可以给到1.5Gi或2Gi。同时,务必设置容器内应用本身的内存限制(比如JVM的-Xmx),并且让这个值小于容器的内存Limit,留出一点空间给系统或其他进程(比如Sidecar),避免“冤杀”。
几个容易踩坑的“深水区”
- “忘记”设置:后果就是Pod可以无限制使用节点资源,俗称“裸奔”。一个Pod就能搞垮一个节点。
- Guaranteed(保证) vs Burstable(突发) vs BestEffort(尽力而为):
- Guaranteed:Requests == Limits(所有容器所有资源)。这是最高优先级,系统保证给足。适合极其核心的组件(如etcd)。
- Burstable:Requests < Limits。这是最常见、最推荐的类型,既有保障又有弹性。
- BestEffort:都不设。优先级最低,资源紧张时最先被干掉。只适合那些无状态、可随时重启、完全不重要的测试任务。
- 节点资源碎片:如果你的Requests设得都很大(比如每个Pod都要2核),而集群里有很多1核、2核的“边角料”资源,就会导致节点看着总资源够,但就是调度不上去新Pod。这时候需要配合集群自动伸缩(CA) 或者优化应用架构。
- Java应用的“内存坑”:JVM的堆内存(
-Xmx)只是Java堆,Pod的内存用量还包括堆外内存(线程栈、直接内存、Native库等)。所以容器内存Limit一定要大于-Xmx,通常建议是-Xmx的1.2到1.5倍。不然怎么死的都不知道。
最后,别忘了动态调整
资源配置不是一劳永逸的。业务在变,代码在变,依赖在变。把它当成一个持续优化的过程。
- 上HPA(水平Pod自动伸缩) 时,HPA是根据当前Pod的实际使用率(Utilization)来扩缩容的,这个使用率的分母,就是Pod的Requests值。所以Requests设得越贴近实际,HPA的反应就越精准。
- 定期(比如每季度)回顾监控,看看你的Requests/Limits是否还符合当前业务形态。资源利用率长期过低?可以尝试安全地下调。频繁触及Limit?那就该扩容了。
行了,不整那些“综上所述”、“让我们一起优化”的虚话了。核心就一句:像了解你家的水电煤气费一样,去了解你服务的资源胃口。 从监控出发,结合业务特性,先求稳,再求省。配好了,运维下班都敢不关手机;配不好,半夜三点等着接电话吧。
去你集群里挑两个服务,按这个思路看看,是不是有能调优的空间?

