首页 > 编程语言 >为什么 java 容器推荐使用 ExitOnOutOfMemoryError 而非 HeapDumpOnOutOfMemoryError ?

为什么 java 容器推荐使用 ExitOnOutOfMemoryError 而非 HeapDumpOnOutOfMemoryError ?

时间:2023-01-08 11:01:43浏览次数:50  
标签:容器 ExitOnOutOfMemoryError 副本 java HeapDumpOnOutOfMemoryError 故障 JVM

前言

好久没写文章了, 今天之所以突然心血来潮, 是因为昨天出现了这样一个情况:

我们公司的某个手机APP后端的用户(customer)微服务出现内存泄露, 导致OutOfMemoryError, 但是因为经过我们精心优化的openjdk容器参数, 这次故障对用户完全无感知. :muscle::muscle::muscle:

那么我们是如何做到的呢?

HeapDumpOnOutOfMemoryError VS ExitOnOutOfMemoryError

我们都知道, 在传统的虚拟机上部署的Java实例. 为了更好地分析问题, 一般都是要加上: -XX:+HeapDumpOnOutOfMemoryError这个参数的. 加这个参数后, 如果遇到内存溢出, 就会自动生成HeapDump, 后面我们可以拿到这个HeapDump来更精确地分析问题.

但是, "大人, 时代变了!"

容器技术的发展, 给传统运维模式带来了巨大的挑战, 这个挑战是革命性的:

  1. 传统的应用都是"永久存在的" vs 容器pod是"短暂临时的存在"
  2. 传统应用扩缩容相对困难 vs 容器扩缩容丝般顺滑
  3. 传统应用运维模式关注点是:"定位问题" vs 容器运维模式是: "快速恢复"
  4. 传统应用一个实例报HeapDumpError就会少一个 vs 容器HeapDump shutdown后可以自动启动, 已达到指定副本数
  5. ...

简单总结一下, 在使用容器平台后, 我们的工作倾向于:

  1. 遇到故障快速失败
  2. 遇到故障快速恢复
  3. 尽量做到用户对故障"无感知"

所以, 针对Java应用容器, 我们也要优化以满足这种需求, 以OutOfMemoryError故障为例:

  1. 遇到故障快速失败, 即尽可能"快速退出, 快速终结"
  2. 有问题java应用容器实例退出后, 新的实例迅速启动填补;
  3. "快速退出, 快速终结", 同时配合LB, 退出和冷启动的过程中用户请求不会分发进来.

-XX:+ExitOnOutOfMemoryError就正好满足这种需求:

传递此参数时,抛出OutOfMemoryError时JVM将立即退出。 如果您想终止应用程序,则可以传递此参数。

细节

让我们重新回顾故障: "我们公司的某个手机APP后端的用户(customer)微服务出现内存泄露, 导致OutOfMemoryError"

该customer应用概述如下:

  1. 无状态
  2. 通过Deployment部署, 有6个副本
  3. 通过SVC提供服务

完整的过程如下:

  1. 6个副本, 其中1个出现OutOfMomoryError
  2. 因为副本的jvm参数配置有: -XX:+ExitOnOutOfMemoryError, 该实例的JVM(PID为1)立即退出.
  3. 因为pid 1进程退出, 此时pod立刻出于Terminating状态, 并且变为:Terminated
  4. 同时, customer的SVC 负载均衡会将该副本从SVC 负载均衡中移除, 用户请求不会被分发到该节点.
  5. K8S检测到副本数和Deployment replicas不一致, 启动1个新的副本.
  6. 待新的部分Readiness Probe 探测通过, customer的SVC负载均衡将这个新的副本加入到负载均衡中, 接收用户请求.

在此过程中, 用户基本上是对后台故障"无感知"的.

当然, 要做到这些, 其实JVM参数以及启动脚本中, 还有很多细节和门道. 如: 启动脚本应该是: exec java ....$*

有机会再写文章分享.

新的疑问

上边一章, 我们解释了"为什么Java容器推荐使用ExitOnOutOfMemoryError而非HeapDumpOnOutOfMemoryError", 但是细心的小伙伴也会发现, 新的配置也会带来新的问题, 比如:

  1. JVM从fullgc -> OutOfMemoryError 这段时间内, 用户的体验还是会下降的, 怎么会是"故障无感知"呢?
  2. 用"ExitOnOutOfMemoryError"代替"HeapDumpOnOutOfMemoryError", 那我怎么定位该问题的根因并解决? 2个参数一起用不是更香么?

这些其实可以通过其他手段来解决:

  1. JVM从fullgc -> OutOfMemoryError 这段时间内, 用户的体验还是会下降的, 怎么会是"故障无感知"呢?
    1. 答: 配置合理的Readiness Probe, 只要Readiness Probe探测失败, K8S就会自动将这个节点从SVC中摘除. 那么合理的Readiness Probe在这里指的就是应用不可用时, Readiness Probe探测必然是失败的. 所以一般不能是探测某个端口是否在监听, 而是应该是探测对应的api是否正常. 如下方.
    2. 答: 通过Prometheus JVM Exporter + Prometheus + AlertManger, 配置合理的AlertRule. 如: "过去X时间, GC total time>5s"告警, 告警后人工介入提前处理.
  2. 用"ExitOnOutOfMemoryError"代替"HeapDumpOnOutOfMemoryError", 那我怎么定位该问题的根因并解决? 2个参数一起用不是更香么?
    1. 答: 目的是为了"快速退出, 快速终结". 毕竟做HeapDump也是需要时间的, 这段时间内可能就会造成体验的下降. 所以, 只有"ExitOnOutOfMemoryError", 退出地越快越好.
    2. 答: 至于分析问题, 可以通过其他手段分析, 如嵌入"Tracing agent"做Tracing的监控, 通过分析故障时的traces定位根因.
    3. Prometheus Alertrule gctime告警后, 人工通过jcmd等命令手动做heapdump.
readinessProbe:
  httpGet:
    path: /actuator/info
    port: 8088
    scheme: HTTP
  initialDelaySeconds: 60
  timeoutSeconds: 3
  periodSeconds: 10
  successThreshold: 1
  failureThreshold: 3

总结

新的技术带来新的变革, 我们需要以发展的眼光看待"最佳实践, 最佳配置".

2016年, 针对虚机部署的Java的最优参数, 在今天来看, 并不一定仍是最优解.

标签:容器,ExitOnOutOfMemoryError,副本,java,HeapDumpOnOutOfMemoryError,故障,JVM
From: https://blog.51cto.com/ewhisper/5996588

相关文章

  • java环境搭建
    Day2-jdk下载(8u201免费)下载地址https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html安装地址    安装完后设置系统变量如下四......
  • 使用 JavaScript 创建一个兔年春节倒数计时器
    我们可以通过多种方式构建JavaScript倒数计时,我在本教程中展示的这个​​兔年春节倒数计时器​​是由HTMLCSS和JavaScript创建的。它的工作方式非常简单,需要两种类......
  • [C++/Java/Py/C#/Ruby/Swift/Go/Scala/Kotlin/Rust/PHP/TS/Elixir/Dart/Racket/Erlang
    目录题解地址代码cppjavapython3C#rubyswiftgolangscalakotlinrustphptypescriptelixirdartracketerlang题解地址https://leetcode.cn/problems/counting-words-with-a-g......
  • Java面试题Day05
    1.说一下HashMap的实现原理?HashMap是基于哈希表的Map接口的非同步实现,此实现提供所有可选的映射操作,并允许使用null值和null键.2.HashMap是如何解决Hash冲突?核心就......
  • 一篇文章彻底弄懂 Java 反射的使用
    文章引用自:一篇文章彻底弄懂Java反射的使用原文链接:https://zhuanlan.zhihu.com/p/378412723说到Java反射,必须先把Java的字节码搞明白了,也就是 Class ,大 Class......
  • 一篇文章彻底搞懂Java的Class到底是什么
    文章引用自:一篇文章彻底搞懂Java的大Class到底是什么原文链接:https://zhuanlan.zhihu.com/p/372418927作者在之前工作中,面试过很多求职者,发现有很多面试者对Java的 Clas......
  • Java 流程控制
    Java流程控制用户交互Scannerjava.util.Scanner是Java5的特征Scanner类是用于获取用户的输入通过Scanner类的next()和nextLine()方法获取输入的字符串读取前需要使......
  • JavaScript-DOM-节点操作
    JavaScript-DOM-节点操作目录JavaScript-DOM-节点操作5.节点操作5.1为什么学节点操作5.2节点概述5.3节点层级6.工作中常见操作1.排他思想(算法)2.百度换肤效果3.表格隔......
  • java学习笔记(九)---maven
    1、概念maven是提供专门用于管理和构建Java项目的工具,它的主要功能有:提供了一套标准化的项目结构 提供了一套标准化的构建流程(编译,测试,打包,发布...)提供了一套依赖管......
  • JavaWeb三大组件之监听器-Listener
    1.JavaWeb三大组件Servlet程序,Listener监听器,Filter过滤器2.Listener监听器监听某种变化(生命周期监听,属性变化监听),做出反应--触发对应方法完成相应任务;监听器实现接口......