前段时间我分享了一篇文章《开源!Pod高负载自动打印JAVA线程堆栈》,介绍了在微服务CPU高负载时,使用Arthas自动捕捉线程信息并推送到Chat的方法。有热心的小伙伴希望增加OOM自动推送堆栈的功能。经过对Arthas的调研发现,在微服务内存使用分析场景中,Arthas同样是通过heapdump来获取堆栈信息,这与使用jmap或Java参数的方式没有本质区别。此外,Pod的内存使用率高并不一定意味着JVM会触发OOM。因此,我更倾向于使用后者,因为它能够准确地在微服务发生OOM时触发heapdump。
01、背景
在k8s场景中,我们通常的做法是给多个微服务的Pod共享挂载持久化存储,用于存储OOM heapdump,这将会带来一些痛点,例如,强依赖持久化存储,如果持久化存储出现故障,将影响多个微服务正常启动,此外,运维通常需要打包heapdump文件,拉取并发送给开发人员,这种工作不仅枯燥乏味,还容易让运维人员感到心累。因此,我们希望在 OOM 生成 heapdump 文件时,不再依赖持久化存储,并能够将 heapdump 文件的下载链接直接推送给开发人员。本文将详细介绍如何实现这一目标。
02、效果展示
当微服务触发 OOM 时,会自动将 heapdump 文件打印到临时存储,并通过脚本将其压缩后上传至 MinIO 对象存储。上传完成后,系统会生成一个下载链接,并以机器人的通知形式发送到指定的群组。开发人员可以自行下载 heapdump 文件,无需为 Pod 挂载持久化存储,也无需运维人员的手动操作。效果图如下:
03、操作步骤
1. 首先需要在微服务基础镜像,做这两件事:
/data/javaHeapDump
/data/gc # 不关注可不创建
#!/bin/sh
minio_url="http://oom-test.yilingyi.com"
kind="非生产环境"
if [[ "$ENV_PROFILES_ACTIVE" =~ 'prod' ]]
then
minio_url="http://oom-prod.yilingyi.com"
kind="生产环境"
fi
gc_share_url="Null"
dump_share_url="Null"
dump_dir=/data/
mc_util_path_url=/data/javaHeapDump/mc
dump_file_name=dump.hprof
## 企业微信通知
qy_url=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxx
...<省略>...
2. 完成上述准备工作后,在微服务的java启动指令添加如下参数(同样,不关注gc的可以不加-Xloggc:/data/gc/gc-%t.log),示例如下
-Xloggc:/data/gc/gc-%t.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:OnOutOfMemoryError=/data/javaHeapDump/dump2minio.sh
-XX:HeapDumpPath=/data/javaHeapDump/dump.hprof
3. 在微服务的yaml配置注入变量ENV_SERVICE_NAME和ENV_PROFILES_ACTIVE,dump2minio.sh脚本需要用到,分别用于文件命名和识别所在环境。
spec:
... ...
template:
metadata:
... ...
spec:
containers:
- name: yilingyi
image: 'xxxxx'
... ...
env:
- name: ENV_SERVICE_NAME
value: yilingyi
- name: ENV_PROFILES_ACTIVE
value: test
04、结 语
完成上述操作后,便能让OOM heapdump不再依赖持久化存储,运维人员也无需再执行重复且枯燥的操作,一起让复杂的东西简单化,重复的事情自动化,本期分享就到这里,谢谢!