容器内Java进程问题造成Pod重启的原因分析

重启原因

容器健康监控探针每3S发送一次readiness、一次liveiness,3s超时,超时未响应再次重发,超过3次未响应,视为POD不健康,自动重启POD。Java应用单次FGC时间过长,当FGC时间出现超过6S时,会偶发极端情况3次拨测正好全部失败,导致POD重启;当GC时间超过9S时,三次拨测大概率全部失败,导致 POD重启。

问题分析

JVM启动会自动获取环境信息,根据CPU、内存、操作系统等,自动优化设置大部分JVM参数,包括各代内存大 小限制、GC算法、GC线程数、编译方式、编译线程数等,目前容器下使用的jdk7/8均不支持获取容器资源限 制,导致JVM使用物理机配置自动优化,优化后启动了33个GC线程,12个编译线程,但实际资源限制,导致GC 时需要较多时间片,单次GC时间变长;

定位方式

1.编写curl脚本,在容器内curl本地127地址拨测接口,偶发出现拨测响应超过3S的;
2.根据重启时间点,在tomcat的access log指定时间点前后1分钟进行查询,发现出现时间暂停,在某一时间段内 无业务请求、无拨测请求;
3.根据重启时间点,在业务日志中查询,出现时间暂停,在某一时间段内无业务处理日志;4
4.使用jstat -gccause pid,通过脚本每秒输出一次,重定向在单个文件中,在出现FGC或YGC时间较久时,容器出现UnHealth事件,随后触发重启POD;

解决方案

调整JVM参数,禁用JVM对部分参数的自动优化,调整后优化参数如下:

  • GC参数调整:
-XX:+UseConcMarkSweepGC 年老代使用cms gc
-XX:+CMSParallelRemarkEnabled 启用cms的并行标记 
-XX:+ParallelRefProcEnabled 启用对finalizer对象的多线程处理 
-XX:+CMSClassUnloadingEnabled 启用对持久代的不使用的class回收 -XX:CMSInitiatingOccupancyFraction=80 年老代cms出发阈值为达到老年代内存的80% -XX:+UseCMSInitiatingOccupancyOnly 仅使用阈值触发,不使用jvm自动调整 -XX:ParallelGCThreads=2 GC并发收集线程数 
-XX:ConcGCThreads=2 GC并发收集线程数 
-XX:MaxTenuringThreshold=4 经过几次YGC后晋升到年老代 
-XX:+DisableExplicitGC 禁用代码内手动System.gc() 
  • 编译参数:
-XX:-CICompilerCountPerCPU 不使用JVM根据CPU的自动计算 
-XX:CICompilerCount=2 强制设定总编译线程数2个 
  • 内存参数:
-Xss256k 线程栈大小
-Xms3g 最小堆内存
-Xmx3g 最大堆内存
-XX:NewSize=1500m 新生代大小 
-XX:MaxNewSize=1500m 新生代最大大小 
-XX:SurvivorRatio=8 新生代存活区比例,默认8
 -XX:MaxDirectMemorySize=256m 堆外内存大小 jdk7: 
-XX:PermSize=256m 永久代大小
-XX:MaxPermSize=256m 永久代最大大小

jdk8:

-XX:MetaspaceSize=256m 元空间大小,jdk8移除Perm区,改为Metaspace 
-XX:MaxMetaspaceSize=256m 元空间最大大小 

你可能感兴趣的:(K8S,JAVA)