01 March 2023

省流版:非核心应用cpu 2c,核心应用多申请;jdk 选择 8u191 版本以上。

k8s 已经是如今云计算的事实标准。

如今云计算发展迅猛,大多数的程序不是部署在阿里云、腾讯云或者AWS之类的共有云,就是部署在公司内部的私有云上,而这些云都是基于 k8s 来打造的。

虽然k8s有专门的运营人员来管理,但是我们java程序才是k8s的最终使用用户。学好k8s,能够帮助我们在云上更好得使用java,从而实现摸鱼目标。

正如本文标题,本文介绍的是k8srequestlimit,这是涉及k8s资源分配的关键参数.

k8s容器调度

k8s是资源调度系统,当有部署需求时,它会从所管理的一堆机器中,跳出来一部分符合条件的机器来部署对应的容器。k8s中使用request 和 limit来描述一个容器所需要的资源。

request : 满足容器启动的最小资源需求。

limit : 容器可以使用的最大资源。

比如,一个容器的内存request 是200MB,limit 是 300MB,那么就会被分配到一台至少有200MB空闲内存的机器上,同时当它使用内存超过300MB时,将其kill。

上面说完了资源描述方式,接下来说一下资源,资源可以分为可压缩资源和不可压缩资源。

可压缩资源:cpu、带宽 不可压缩资源:内存、硬盘

可压缩资源,指资源不够的时候,也还能运行,但是会慢一些;cpu和带宽都属于这一类。

不可压缩资源,指资源不够时,就无法运行。内存不够了,就会触发系统的oom kiil。

云计算中的超卖

即便我们已经警告过用户了,用户依然会成倍的申请得资源。 – google 云计算副总裁

ppqq新增的所有算力,都会被浪费。

因为用户总是想用尽可能多的资源来保障服务质量,所以现实中,大多数集群都是超额申请资源,同时资源使用率非常低。

此处插入两张图。

从而导致资源有巨大的浪费。比如,一台物理机器,40c,老实人做法:只分配40c的资源,比如4c * 10. 结果物理机的cpu使用率只有5%.造成了大量的浪费

结合实际应用使用率的现状,为了提升整体资源的使用率,云平台就出现了超卖现象。

比如在一个40c的机器上,分配超过40c的容器,比如80c,甚至400c。

cpu 是容易被超卖的资源,常见的超卖倍数:2~10倍,而内存/硬盘则不太容易,超卖风险太高,一般超卖比例在0-10%.

cpu 限流问题

k8s中使用cfs算法进行cpu调度,该算法每100ms调度一次cpu,如果应用恰好在这100ms有徒增的cpu需求,超过了设定的limit,就会触发cpu限流,导致应用在100ms剩下的时间内无cpu可用,从而导致应用rt上涨,出现超时。

此处贴图。

因为调度周期是100ms,而传统监控工具采集数据间隔往往是秒级甚至分钟级,所以从监控上很难发现是否存在cpu限流,最好的解决办法是结合应用的slo来分析,如果超时次数不满足slo,则可以尝试增大cpu来避免出现cpu限流问题。

java 应用在k8s上部署的建议

基于上述提到的问题,同上加上java语言非常早,不像go之类的语言和云适配器非常好,所以需要我们手动干预,来使java和云更亲和。

版本:选择jdk8u191以上的版本,因为从这个版本开始,jvm才能读取到容器正确的cpu核数,之前的版本会读取到物理机的核心数;

cpu :

  • 核心低延迟/cpu密集应用设置足量的cpu来避免cpu限流。
  • 非核心应用建议2个cpu起步,因为jvm识别到系统为1cpu时,会做一些串行化的设置,比如启用SerialGC.

内存:

  • 保持容器内存使用率接近70~80%,避免浪费,毕竟这是不可压缩资源,浪费了内存就是浪费了真金白银。
  • 设置heap大小上限以及non-heap大小上限,防止应用使用了超过limit的内存,导致被kill。如果没有设置上限,同时使用了低于8u191的版本,jvm将会读取到物理机的内存,自动将heap的最大值设置为物理机内存的1/4,比如物理机为128g,那么jvm相当于-Xmx32g 。heap 上限可以使用-Xmx设置,non0heap可以使用-MaxMetaSpaceSize(jdk8+) 或者 -MaxPermGenSize(jdk6-7)

我们曾经线上一台机器的jvm参数是”-Xms4g -Xms4g”, 实际它的堆上限是32g,相当于一个定时炸弹运行在线上。

总结

  • 新应用部署:
    • jdk8u191+
    • cpu : 普通应用 2c;cpu密集/核心低延迟服务,尽量多,直到满足slo。
    • 内存:使用率70~80%,
  • 降本增效:
    • 优先内存