K8s工程化:K8s中的Java应用出现OOM后怎么办?

2023-11-20


完整代码在文末

背景

前段时间,线上系统出现了两次持续时间比较长的事故。这两次事故暴露我在某些方面的不足。同时,也意识到在SRE这个领域,经验的重要性。

事故过程中,我们发现大量的FullGC。当时,我们想到了要dump内存出来分析,可惜发现没有加-XX:HeapDumpPath参数。同时,我们也发现,如果dump出来了,我们也没法拿到dump出来的文件。因为我们的应用是跑在K8s中的。

方案调研

经复盘,我们得到一个action:在Java应用出现OOM时,将内存dump出来,并持久化,并且方便分析。

这个action可以细分为两个任务:

  1. OOM时,dump内存出来;

  2. 提供一种途径方便分析。

经过权衡,任务2的优先级是可以降低的。puvad只要把任务1做好就可以。所以,这两个任务最终变成:在Java应用出现OOM时,将内存dump到NAS中。

笔者在网上搜索一通,看到的方案基本就是启动一个sidecar容器,与应用共享一个目录。然后监控这个目录,发现内容就上传到s3这类对象存储中。

这种方案的问题在于:

  1. sidecar在传输过程,有出现问题的风险;

  2. 为了OOM这个小概率事件启动一个sidecar,资源有点浪费。

个人觉得,Java应用的Pod应该只负责将OOM时的内存dump到NAS即可,其它事情应该由其它Pod完成。

具体实现

以下方案是基于Helm自动化部署。如果你使用的是其它自动化部署工具,思路大体相同。

准备NFS服务

这部分不是本文范畴。

Java应用启动时参数配置

在Dockerfile中必须将变量$JAVA_OPTS加入到启动参数中。

FROM openjdk:11.0.12-jre-buster
COPY target/app.jar /app.jar
CMD java -jar $JAVA_OPTS /app.jar
加入InitContainers

作用:创建符合指定规则的Dump目录(注意DUMP_FOLDER变量的定义)。如下代码,在init容器启动后,它会创建目录:/nfs/dump/default/jvm-oom-example/10.233.66.38 。在应用出现OOM,内存文件会被dump在此目录下。

initContainers:
- name: init
  image: registry.cn-shenzhen.aliyuncs.com/aliacs-app-catalog/busybox:1.30.1
  command: ['sh', '-c', 'echo $DUMP_FOLDER;mkdir -p $DUMP_FOLDER']
  {{- with .Values.volumeMounts }}
  volumeMounts:
  {{- toYaml . | nindent 12 }}
  {{- end }}
  env:
  - name: MY_NODE_NAME
      valueFrom:
      fieldRef:
          fieldPath: spec.nodeName
  - name: MY_POD_NAME
      valueFrom:
      fieldRef:
          fieldPath: metadata.name
  - name: MY_POD_NAMESPACE
      valueFrom:
      fieldRef:
          fieldPath: metadata.namespace
  - name: MY_POD_IP
      valueFrom:
      fieldRef:
          fieldPath: status.podIP
  - name: DUMP_FOLDER
      value: "/nfs/dump/$(MY_POD_NAMESPACE)/{{ include "app.fullname" . }}/$(MY_POD_IP)"
配置应用容器

我们要做的,其实就是设置JAVA_OPTS环境变量。这里要注意的是JAVA_OPTS可以由三部分组成的:

  1. 内存大小设置,比如:-Xmx640M Xms640M 这类;

  2. GC算法设置,比如:-XX:+UseSerialGC

  3. JVM日志设置,比如:-XX:ErrorFile=/dump/hs_err_pid%p.log -XX:HeapDumpPath=/dump。

1,2部分应该是由用户决定。第3部分是由平台决定的。

所以,我们的配置JAVA_OPTS分成两部分:DUMP_ARGS 和 用户的JVM配置。代码如下:

containers:
- name: {{ .Chart.Name }}
  {{- with .Values.volumeMounts }}
  volumeMounts:
    {{- toYaml . | nindent 12 }}
  {{- end }}
  env:
    - name: MY_NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName
    - name: MY_POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: MY_POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: MY_POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: DUMP_FOLDER
      value: "/nfs/dump/$(MY_POD_NAMESPACE)/{{ include "app.fullname" . }}/$(MY_POD_IP)"
    - name: DUMP_ARGS
      value: "-XX:ErrorFile=$(DUMP_FOLDER)/hs_err_pid.log  -XX:HeapDumpPath=$(DUMP_FOLDER) -XX:+HeapDumpOnOutOfMemoryError"
    - name: JAVA_OPTS
      value: "{{.Values.javaOpts}} $(DUMP_ARGS)"

最终效果

[vagrant@k8s-3 jvm-oom]$ pwd
/persistentvolumes/dump/default/jvm-oom
[vagrant@k8s-3 jvm-oom]$ tree
.
├── 10.233.66.37
└── 10.233.66.38
    └── java_pid6.hprof

小结

这个方案并不是没有缺点。比如每次Pod启动都会创建一个目录,不论是否出现OOM。当然,这个缺点的解决方案也很简单,另启一个Pod负责清理就好了。

完成代码地址:https://github.com/zacker330/jvm-oom-example

欢迎关注公众:持续交付实践指南。

往期好文:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

K8s工程化:K8s中的Java应用出现OOM后怎么办? 的相关文章

  • Java 9 中可以使用提前编译吗?

    As per JEP 295 http openjdk java net jeps 295 任何 JDK 模块 类或用户代码的 AOT 编译都是实验性的 JDK 9 中不支持 要使用 AOT 化的 java base 模块 用户必须编译该模
  • 将 JSON Map 传递到 Spring MVC 控制器

    我正在尝试将 Map 的 JSON 表示形式作为 POST 参数发送到我的控制器中 RequestMapping value search do method RequestMethod GET consumes application j
  • 隐藏类的 System.out.print 调用

    我正在使用 java 库 jar 文件 该文件的作者放入了一堆System out print and System out printlns 有没有办法隐藏特定对象的这些消息 编辑 看起来jar文件似乎正在创建一堆线程 并且每个线程都有它
  • ASM之前看一下maxStack指令吗?

    我正在尝试使用 ASM 库将字节代码转换为不同的格式 这可以使用 MethodVisitor 来完成 就像这个简单的测试代码一样 return new MethodVisitor ASM7 Override public void visi
  • Jodatime 日期格式

    是否可以格式化 JodaTime 日期 这是代码 private static LocalDate priorDay LocalDate date1 do date1 date1 plusDays 1 while date1 getDayO
  • 总结二维数组

    鉴于我当前的程序 我希望它在用户输入所有值后计算每列和每行的总和 我当前的代码似乎只是将数组的值加倍 这不是我想要做的 例如 如果用户输入具有以下值 1 2 3 2 3 4 3 4 5 的 3x3 矩阵 则看起来就像我在下面的程序中对其进行
  • Spring 术语中命令、表单、业务和实体对象之间的区别?

    我试图理解这些对象在松散耦合系统方面的差异 业务对象与实体对象相同吗 我可以使用 MVC 中的业务或实体对象作为我的命令对象吗 命令对象与表单对象相同吗 只是寻找 Spring 术语和用法中对象类型的说明 我在 stackoverflow
  • Java 反射:如何检索匿名内部类?

    我在另一个类中有一个匿名内部类 SomeClass Both SomeClass class getClasses and SomeClass class getDeclaredClasses 返回空数组 我在中找不到一些关于此的提示Cla
  • 在java中是否可以使用反射创建没有无参数构造函数的“空白”类实例?

    我有一个没有默认构造函数的类 我需要一种方法来获取此类的 空白 实例 空白 意味着实例化后所有类字段都应具有默认值 如 null 0 等 我问这个问题是因为我需要能够序列化 反序列化大对象树 而且我无法访问该对象类的源 并且类既没有默认构造
  • 驱动程序信息:driver.version:未知,使用 ChromeDriver v78.0.3904.70 和 Chrome 浏览器 v78.0.3904.97

    我使用的是java 1 8和chrome浏览器版本78 0 3904 97 我正在尝试使用 chrome 驱动程序版本执行我的 selenium 脚本代码78 0 3904 70 但在执行时我面临以下问题并且 chrome 立即崩溃 Pic
  • activemq 的优先级

    我们目前正在使用 JMS 和 activemq 5 5 1 开发一个应用程序 我们想为某些消息定义更高的优先级 这将使它们首先被消耗 设置生产者和消费者后 通过spring 3 1 JMSTemplate 优先级并不能完全发挥作用 事实上
  • Akka 和 spring 配置

    我正在尝试将 akka 与 spring 结合起来 但没有成功 基本上 我的应用程序似乎不习惯读取 akka 模式 具有架构的 service context xml 的一部分
  • Docker 中的 Electron:SIGTRAP、ELIFECYCLE、errno1

    介绍 我有一个演示电子应用程序 运行时运行良好npm run start从我的Mac 我有兴趣将应用程序移至 Docker 容器中 但是当docker compose达到electron命令步骤 我得到以下信息 gt electron no
  • 如何告诉 IntelliJ 使用 Java 1.6 JDK 启动 gradle?

    一个简单的问题 即使经过几个小时的尝试和搜索 我也无法弄清楚 我安装了 Java 6 和 7 如何告诉 IntelliJ 使用 JDK 版本 1 6 启动 Gradle 构建 无论我做什么 IntelliJ 都会以以下方式开始我的 grad
  • Microsoft JDBC 中的 JTDS 属性相当于什么?

    我正在将 JTDS 连接更改为 Microsoft JDBC 并且我看到存在于http jtds sourceforge net faq html http jtds sourceforge net faq htmlMicrosoft JD
  • 如何修改生成的SOAP请求?

    我正处于创建输出拦截器并从 SOAP 消息中获取 OuputStream 的阶段 但是 如何在将 SOAP 信封发送到端点之前对其进行修改呢 我想删除一些 xml 元素 一种方法是获取文档并通过 XSLT 转换运行它 您可以通过调用来获取拦
  • 如何在 Servlet 中打开弹出窗口,然后重定向页面

    我想在调用 servlet 时打开一个弹出窗口 然后想将 servlet 重定向到某个 jsp page 这就是我所做的 protected void doGet HttpServletRequest request HttpServlet
  • 线程“main”中出现异常 java.lang.UnsatisfiedLinkError: ... \jzmq.dll: 找不到依赖库

    我有一个使用 ZMQ 的 java 应用程序 我已经能够在我的 Win7 PC 上运行它 我将 jzmq dll 放在 jar 可执行文件所在的同一文件夹中 然后通过命令 java jar myapp jar 运行它 我的下一步是将其移至服
  • 使用 Hibernate 防止无限循环数据检索

    我想知道 想象一个场景 例如 POJO public class User private String userName private String name private String surname private List
  • 安卓框架?

    是否有任何框架比构建 Android 应用程序更容易 您会对其中一个感兴趣吗 很快就会有 我正在开发 DroidFu 一个 Android 共享库 它将为您提供 活动 和服务 中直接提供大量实用功能 例如生成列表和错误对话框 检查 Inte

随机推荐

  • 数据分析---arXiv论文种类分类

    论文种类分类 4 1 任务说明 主题 论文分类 数据建模任务 利用已有数据建模 对新论文进行类别分类 内容 使用论文标题完成类别分类 4 2 数据处理步骤 在原始arxiv论文中论文都有对应的类别 而论文类别是作者填写的 在本次任务中可以借
  • 修改环境变量后,导致一些常用命令失效,如ll,ls,vi不能用

    因为一不小心将linux的环境变量修改错误 导致ll之类的常用命令都不能用 很是苦恼 通过百度查询 原来在敲命令时 敲完整的命令路径 还是可以的 原文地址 http www cnblogs com zhbsh archive 2011 05
  • 1141 二维数组的输入和输出

    题目描述 输入m行n列的二维数组的值 再按行列形式输出 输入要求 第一行输入m n代表行数和列数 接着输入具体的m n个元素 输出要求 按行列形式换行输出 每一个数据后面都有空格 一行输出完毕后换行 输入样例 2 5 1 4 6 23 1
  • Qt实现窗口关闭时提示确认退出

    Qt实现窗口关闭时提示确认退出 在Qt中 当用户点击窗口关闭按钮时 程序会直接退出 这样可能会导致数据丢失或其他不必要的操作 为了提高用户体验 我们可以在窗口关闭前给出一个提示框 询问用户是否确认退出 一 实现思路 通过重写QWidget类
  • kaggle数据集的下载

    感谢阅读本文 喜欢请收藏点赞 准备工作 1 安装kaggle库 2 注册登录kaggle账户 3 kaggle json的下载与使用 4 下载数据集 文件保存路径 准备工作 1 安装kaggle库 2 注册登录kaggle账户 点我跳转 没
  • R-INLA Project目录

    集成嵌套拉普拉斯近似法 INLA 是一种近似贝叶斯推断的方法 在过去的几年里 由于其速度和通过R INLA软件包的易用性 它已经成为马尔科夫链蒙特卡洛等其他方法的替代品 尽管INLA方法的重点是可以表达为潜伏高斯马尔可夫随机场 GMRF 的
  • SpringMVC视图解析器

    SpringMVC视图解析器 前言 在前一篇博客中讲了SpringMVC的Controller控制器 在这篇博客中将接着介绍一下SpringMVC视图解析器 当我们对SpringMVC控制的资源发起请求时 这些请求都会被SpringMVC的
  • ES: 设置默认值

    场景 XX对象的告警个数字段是数字 优先级字段是数字 排序要求 优先告警个数大 gt 小 其次优先级大 gt 小 问题 告警个数字段不存在或者值为0的情况是等价的 排序上应该是平等的 不应该存在0的大于字段不存在的 处理 对没有告警个数字段
  • Obsidian 使用 Livesync 同步数据

    Obsidian 使用 Livesync 同步数据 之前一直使用 icloud 同步我的 obsidian 笔记 同时定期使用 git 备份笔记 但是前段时间因为在 ios 上误删了一个文件夹 导致我的 icloud 桌面端和手机端的笔记不
  • Ubuntu9.04太多乱码(中文不能正常显示)

    最近在使用Ubuntu9 04的过程中 发现有好多地方都出现乱码 其实是中文不能正常显示 现在把我所遇到的所有乱码问题集中一下 方便以后查阅参考 一 Flash乱码 在终端输入 sudo gedit etc fonts conf d 49
  • linux系统安装python3.9.2

    1 下载安装包 下载地址 https www python org downloads release python 392 在这里插入图片描述 2 下载Python3编译的依赖包 yum install y gcc patch libff
  • Ajax——Ajax的同步与异步以及代码封装(jQuery)

    文章总结目录 1 Ajax的异步与同步 1 1 同步与异步概念 1 2 Ajax在代码上的实现 1 3 Ajax同步与异步使用的场景 2 Ajax代码的封装 2 1 Ajax代码封装的原因 2 2 如何实现Ajax代码的封装 2 3 Aja
  • 为啥MyBatis-Plus 分页插件不生效?

    描述 项目中用到boot 整合 mybatis plus 个人在使用分页条件查询的时候一直查不出 total pages 终于找到原因了 环境
  • 清华大学AIGC发展研究报告1.0版震撼发布!192页PPT

    来源 清元宇宙 人工智能无疑是2023年最受关注的科技热点 作为将会掀起人类再一次生产力革命的重大技术突破 人工智能受到了全球范围内各领域人士的高度关注 近日 清华大学沈阳教授团队发布了 AIGC发展研究报告1 0版 总计192页 分为技术
  • java parser .java_Stanford Parser使用之 Eclipse+java调用

    官网 Download Stanford Parser version 3 2 0 stanford parser full 2013 06 20 zip 解压缩 stanford parser full 2013 06 20 zip st
  • 信息安全期末题库

    大多数应用程序 操作系统和实用程序都用高级程序语言或汇编语言编写 所编写的程序称为源程序 源程序需经过编译 链接 装入三个阶段才能装入主存运行 逻辑地址转换为物理地址的过程称为地址重定位 包括 静态地址重定位 地址转换在进程执行前一次完成
  • matlab基础语法2_matlab的函数_句柄

    函数是模块化 抽象化的实施者 如何查看matlab的内建函数 查看matlab内建的函数 mean m 计算平均数 在命令行窗口输入edit which mean m 会跳出一个 m文件 gt gt edit which mean m fu
  • Gauss_Seidel method with python

    Gauss Seidel method with python from wikipedia https en wikipedia org wiki Gauss E2 80 93Seidel method import numpy as n
  • 三星A5显示服务器未响应,三星A5手机死机了 屏幕一直亮着 按什么键都没反应==求解答...

    三星A5功能特征 双面2 5D玻璃金属边框设计 两种材质圆融贴合 Galaxy A5 2016 在外观上寻求突破 精心选用双面2 5D玻璃 SamsungGalaxy A5 2016 A7 2016 A时代 不玩不快 Galaxy A系列活
  • K8s工程化:K8s中的Java应用出现OOM后怎么办?

    完整代码在文末 背景 前段时间 线上系统出现了两次持续时间比较长的事故 这两次事故暴露我在某些方面的不足 同时 也意识到在SRE这个领域 经验的重要性 事故过程中 我们发现大量的FullGC 当时 我们想到了要dump内存出来分析 可惜发现