java项目在k8s 中oom处理
oom情况发生一般都是因为内存使用过高导致,最好是走查代码分析出内存占用高的具体原因。 此篇文章说明什么情况下会出现oom,以及如何从运维层面暂缓oom发生。真正解决内存占用还是需要分析代码以及java 堆栈. 不想了解细节,参见最后的java内存配置
发生 oom 情况分类
- oom
- 一般说的是java堆内存不够,频繁GC释放不了足够内存来完成新的内存申请导致,这种情况就是jvm内存配置限制了内存申请,解决方式就是调整内存限制大小。
- oom killer
- oom killer是linux系统对内存管理的一种方式,当操作系统内存不够用 linux会启动一个oom进程根据在运行的进程的内存占用通过oom_scope和oom_scope_adj 决定杀死某个进程来释放内存(一般都是会干掉内存最高的,详细可以参见 oom_scope 和oom_scope_adj 参数)
java 中jvm内存配置
java 中一般通过配置java的启动参数配置jvm的内存使用情况例如-Xms2048m -Xmx2048m 不过在当前容器化环境一般都会配置POD的资源限制,而openjdk 新版本已经能够识别到容器的资源限制,所以可以不配置jvm。让jdk自动选择。但是jvm默认时使用总内存的一半,例如:k8s中内存限制为1024M,那么jvm只会使用约512M的内存,哪怕jvm已经放生oom,jvm也不会在申请,这样就导致通过k8s的配置和内存使用不统一,可以通过配置jvm参数解决此问题-XX:MaxRAMPercentage=90.0 -XX:MinRAMPercentage=60.0 最高使用k8s 限制内存的90%
oom killer 如何避免
配置POD 内存资源限制,如果不配置 jvm会按照宿主机的内存自动分配。当宿主机内存不够用,这种POD非常容易被kill掉
配置POD 内存的request和limit一样大,这样k8s会调整进程的oom_scope_adj和oom_adj值来保证操作系统不kill掉这种pod(不是绝对的). 如果内存使用超过 limit同样会被干掉
项目中java内存配置
- 使用推荐的基础镜像
- 推荐jdk
- 列表中的镜像能自动发现k8s的资源限制
- Dockerfile 中配置jvm默认分配比例
- -XX:MaxRAMPercentage=70.0 -XX:MinRAMPercentage=50.0
- 可以参见Wiki
- 配置容器的内存限制
- jenkins 使用cm-service2 chart包发布的时候配置
- --set resources.limits.memory="2Gi" \
- 默认就是2Gi, 如果需要修改则通过此配置修改
通过以上三项配置后无需配置jvm的参数,如果内存仍然不够用(java 发生oom)修改jenkins中的内存限制重新发布即可
特殊情况:如果服务的 可用性非常高,不像被操作系统oom killer那么配置request和limits为相同值
--set resources.limits.memory="2Gi" \ --set resources.requests.memory="2Gi" \