当前位置: 首页 > news >正文

k8s容器java应用频繁重启问题排查 OOM方向

1.排查是否为OOM导致的服务重启

1.1检查k8s yaml

{"env":[{"name":"JAVA_OPTS","value":"-Xmx4260m-Xms4260m  -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError=/quitJava.sh-XX:HeapDumpPath=/var/logs/dump/app.hprof -XX:+PrintGCDetails-XX:+PrintGCDateStamps -Xloggc:/var/logs/dump/gc-app.log -Drocketmq.client.logLevel=error"}

上述可以看到在发生oom时会在/var/logs/dump目录下生成app.hprof 的dump文件,但实际查看未发现产生该文件

2.排查是否为k8s探针导致的服务重启

2.1 k8s三种探针

2.1.1Liveness Probe(存活探针)

作用:检测容器是否“活着”。
目标:判断应用进程是否挂掉或进入无法恢复的状态。
触发动作:如果探针失败,Kubernetes 会 重启容器(Restart Container)。
使用场景:应用死锁(thread lock)、无限循环、内存溢出后无法自我恢复。

Liveness 保证应用不挂死,失败会强制重启容器。
示例:

livenessProbe:httpGet:path: /healthport: 8080initialDelaySeconds: 30  # 等待应用启动periodSeconds: 10        # 每 10 秒检测一次failureThreshold: 3      # 连续 3 次失败才重启

2.1.2 Readiness Probe(就绪探针)

作用:检测容器是否“准备好接收流量”。
目标:判断应用是否可以处理请求。
触发动作:
探针失败时,Kubernetes 会 把 Pod 从 Service 的 Endpoints 中移除,不再接收流量。
容器不会被重启(与 Liveness 不同)。
使用场景:应用启动慢、依赖初始化(DB、缓存)
高负载下暂时无法处理请求

Readiness 控制流量,确保 Pod 只在准备好时才接收请求。
示例:

readinessProbe:httpGet:path: /readyport: 8080initialDelaySeconds: 10periodSeconds: 5failureThreshold: 3

2.1.3 Startup Probe(启动探针)

作用:专门用于 慢启动的应用,防止 Liveness 探针过早重启。
目标:在应用完全启动之前,延迟 Liveness 的判断。
触发动作:如果启动探针失败,Kubernetes 会 重启容器
成功后,Liveness 和 Readiness 才开始工作
使用场景:
Java、Spring Boot、Tomcat 等启动时间长的应用
避免 Liveness 在启动期间误杀容器

Startup 保护容器启动,长时间慢启动不会被误判为死掉。

示例:

startupProbe:httpGet:path: /healthport: 8080initialDelaySeconds: 0periodSeconds: 10failureThreshold: 30  # 等待 5 分钟

2.2 排查问题

根据2.1的内容,推断可能是Liveness Probe导致服务被kill重启,查看实际的探针脚本

livenessProbe:exec:command:- /bin/bash- '-c'- >r2=$(curl -i --max-time 10'http://localhost:8099/health_check' | awk 'NR==1 {print}')echo $r2if [[ ! "$r2" =~ "200" ]]; thenecho "health未就绪"exit 1fifailureThreshold: 5initialDelaySeconds: 40periodSeconds: 5successThreshold: 1timeoutSeconds: 10

由上述脚本可知存活探针主要是检测/health_check 返回状态码是否为200来判断应用是否正常,如果非200则会退出容器进行重启。
为了检查实际的检测情况,我们对脚本进行了修改,再每次探针执行时都进行状态码的打印,最终修改为

livenessProbe:exec:command:- /bin/bash- '-c'- >r2=$(curl -i --max-time 10'http://localhost:8099/health_check' | awk 'NR==1 {print}')echo $r2svc=appdate_hms=$(date '+%Y-%m-%d %H:%M:%S')echo -e "\n${date_hms} ===== $r2 =====" >> /var/logs/pid.txtif [[ ! "$r2" =~ "200" ]]; thenecho "health未就绪"exit 1fifailureThreshold: 5initialDelaySeconds: 40periodSeconds: 5successThreshold: 1timeoutSeconds: 10

等待服务自动重启后,发现在重启期间存活探针调用的/health接口未出现非200的状态码,说明不是探针导致的服务重启

3.连接k8s集群查看pod实际启动情况

3.1 执行指令查看

3.1.1 连接k8s集群

进入阿里云容器服务 Kubernetes版ACK,拿到kubeConfig,
在这里插入图片描述
将kubeConfig复制到本地,并新建一个文件/Users/xxx/Utils/ecoflow-sit-cloud.yaml
在这里插入图片描述

3.1.2 查看pod信息

在这里插入图片描述

3.1.3 执行命令

第一步
export KUBECONFIG=/Users/xxx/Utils/ecoflow-sit-cloud.yaml
第二步 查看容器退出原因
kubectl describe pod app-deployment-67699fcf96-m255k -n default | grep -A5 "Last State"

在这里插入图片描述
发现最终还是oom导致的重启,但是为什么没有产生dump文件?

4.原因分析

4.1 未产生dump文件的原因

4.1.1 查看启动参数

{"env":[{"name":"JAVA_OPTS","value":"-Xmx4260m-Xms4260m  -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError=/quitJava.sh-XX:HeapDumpPath=/var/logs/dump/app.hprof -XX:+PrintGCDetails-XX:+PrintGCDateStamps -Xloggc:/var/logs/dump/gc-app.log -Drocketmq.client.logLevel=error"}

发现在oom是会执行脚本quitJava.sh

pid=1 # ......1.........
kill -15 $pid
sleep 5s
kill -9 $pid

脚本首先会kill掉java进程,-15代表会等待后续的处理完成,但隔5秒后直接kill -9强制对进程进行删除

4.1.2 没有产生dump文件的原因

因为生产dump文件需要一定时间,但在oom时执行的脚本只等待5秒钟。所以实际情况是在5秒内未生成完dump文件,进程被kill掉了

5. 排查方式

5.1 修改oom执行脚本

pid=1 # ......1.........
date_hms=$(date '+%Y-%m-%d %H:%M:%S')
jpid=$(ps -ef | grep java | awk 'NR==2 {print $1}')
jstack ${jpid} > ${jstack_name}/var/logs/dump_jstack_${date_hms}.txt
kill -15 $pid
sleep 60s
kill -9 $pid

延时60秒进行kill -9 ,给dump日志足够的生成时间,并且增加jstack,在发生上述情况的时候可以记录相关线程的信息,方便后续排查oom问题

5.2 修改k8s pod yaml

在存活探针脚本中增加gc和jvm内存的相关日志,方便查看整体的内存变化趋势,用于排查当前的oom问题

          livenessProbe:exec:command:- /bin/bash- '-c'- >r2=$(curl -i --max-time 10'http://localhost:8099/health_check' | awk 'NR==1 {print}')jpid=$(ps -ef | grep java | awk 'NR==2 {print $1}')svc=appdate_hms=$(date '+%Y-%m-%d %H:%M:%S')jstat_gc_name=/var/logs/${svc}_jstat_gc.txtjstat_gcutil_name=/var/logs/${svc}_jstat_gcutil.txtecho -e "\n${date_hms} ===== jstat -gc =====" >> $jstat_gc_nameecho -e "\n${date_hms} ===== jstat -gcutil =====" >> $jstat_gcutil_namejstat -gc $(jps -l | grep /app.jar | awk '{print $1}') 1000 1 >> $jstat_gc_namejstat -gcutil $(jps -l | grep /app.jar | awk '{print $1}') 1000 1 >> $jstat_gcutil_nameecho $r2if [[ ! "$r2" =~ "200" ]]; thenecho "health未就绪"exit 1fifailureThreshold: 5initialDelaySeconds: 40periodSeconds: 12successThreshold: 1timeoutSeconds: 10

最终gc和内存执行效果
在这里插入图片描述
在这里插入图片描述

http://www.dtcms.com/a/490911.html

相关文章:

  • 宁夏建设工程造价网站做pc端网站新闻
  • Spring Boot + Filebeat + ELK日志在线查看
  • 使用高性能流式的库SpreadCheetah创建EXCEL文件
  • 【西瓜播放器+Vue】前端实现网页短视频:上下滑动、自动播放、显示视频信息等
  • 软件下载网站模版html软件下载手机版
  • 哪些平台可以免费推广广州百度提升优化
  • Redis-缓存问题(穿透、击穿、雪崩)
  • Mysql数据库系统库数据恢复
  • 服务器数据恢复—RAID5硬盘掉线,热备盘未启用如何恢复raid5阵列数据?
  • 在 Linux 服务器上配置 SFTP 的完整指南(2025 最新安全实践)
  • pytorch 数据加载加速
  • 网站建设平台设备荣耀手机官网
  • 调用apisix admin 接口创建资源
  • 迅为RK3568开发板OpenHarmony系统南向驱动开发手册-pdf配置 rk3568_uart_config.hcs
  • 中兴通讯的网站建设分析wordpress安装后要删除哪些文件
  • 建设银行对账单查询网站简述电子商务网站开发的主要步骤
  • ARMA模型
  • 智慧园区:引领城市未来发展新趋势
  • python命名约定 私有变量 保护变量 公共变量
  • 气泡图 vs 散点图:什么时候加第三维?
  • 西安网站开发工程师wordpress+中文版
  • 网页设计网站源代码淘宝网站的建设目的
  • 分布式系统的幂等性设计:从理论到生产实践
  • Advanced Port Scanner,极速端口扫描利器
  • 字节面试题
  • 个人项目开发(2) 基于MFA实现的双重登录验证
  • 邢台做移动网站公司电话号码中国设计之家
  • 丹阳高铁站对面的规划打开这个网站你会回来感谢我的
  • 2025年--Lc194-516. 最长回文子序列(动态规划在字符串的应用,需要二刷)--Java版
  • [HTML]播放wav格式音频