让JVM感知K8s资源限制
无感知导致的问题
当我们在K8s中Deployments配置资源限制和预留的时候,比如设置最大内存为500M。但是宿主机的总内存为8G,这时候Pod启动后会超出内存限制,被Deployments杀掉。但为了维护设置的副本数量又创建新的,如此反复。
原因是默认情况JVM默认最大堆空间为系统总内存的1/4,在容器中没有感知到集群为Pod设置的资源限制,而是按宿主机的内存算的,所以最终超过限制内存。
解决方案
解决思路有两种:
- 一种是按资源限制算好,在 Java 启动参数中设置堆内存大小,保证不超限制
- 另一种是让JVM感知到容器资源限制,按这个值来分配内存
Java SE 8u131向后 和 JDK 9 都有参数支持:如下
-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap
但是如果资源限制默认分配1/4有点浪费,因为一般一个Pod就跑这一个主要进程,所以可以改下这个默认值,如下:
# 2 代表1/2
-XX:MaxRAMFraction=2
这样配置并不代表就是资源限制的1/2,因为除了堆内存还有其他堆外内存需要空间,所以实际值要远小于1/2。网上有人在测试环境设置1,代表100%,但是我试过之后还是超过资源限制了,所以选了2,实际需要根据情况决定。