为什么 java 容器推荐使用 ExitOnOutOfMemoryError 而非 HeapDumpOnOutOfMemoryError ?
前言
好久没写文章了, 今天之所以突然心血来潮, 是因为昨天出现了这样一个情况:
我们公司的某个手机APP后端的用户(customer)微服务出现内存泄露, 导致OutOfMemoryError, 但是因为经过我们精心优化的openjdk容器参数, 这次故障对用户完全无感知.
那么我们是如何做到的呢?
HeapDumpOnOutOfMemoryError VS ExitOnOutOfMemoryError
我们都知道, 在传统的虚拟机上部署的Java实例. 为了更好地分析问题, 一般都是要加上: -XX:+HeapDumpOnOutOfMemoryError这个参数的. 加这个参数后, 如果遇到内存溢出, 就会自动生成HeapDump, 后面我们可以拿到这个HeapDump来更精确地分析问题.
但是, "大人, 时代变了!"
容器技术的发展, 给传统运维模式带来了巨大的挑战, 这个挑战是革命性的:
- 传统的应用都是"永久存在的" vs 容器pod是"短暂临时的存在"
- 传统应用扩缩容相对困难 vs 容器扩缩容丝般顺滑
- 传统应用运维模式关注点是:"定位问题" vs 容器运维模式是: "快速恢复"
- 传统应用一个实例报HeapDumpError就会少一个 vs 容器HeapDump shutdown后可以自动启动, 已达到指定副本数
- ...
简单总结一下, 在使用容器平台后, 我们的工作倾向于:
- 遇到故障快速失败
- 遇到故障快速恢复
- 尽量做到用户对故障"无感知"
所以, 针对Java应用容器, 我们也要优化以满足这种需求, 以OutOfMemoryError故障为例:
- 遇到故障快速失败, 即尽可能"快速退出, 快速终结"
- 有问题java应用容器实例退出后, 新的实例迅速启动填补;
- "快速退出, 快速终结", 同时配合LB, 退出和冷启动的过程中用户请求不会分发进来.
-XX:+ExitOnOutOfMemoryError就正好满足这种需求:
传递此参数时,抛出OutOfMemoryError时JVM将立即退出。 如果您想终止应用程序,则可以传递此参数。
细节
让我们重新回顾故障: "我们公司的某个手机APP后端的用户(customer)微服务出现内存泄露, 导致OutOfMemoryError"
该customer应用概述如下:
- 无状态
- 通过Deployment部署, 有6个副本
- 通过SVC提供服务
完整的过程如下:
- 6个副本, 其中1个出现
OutOfMomoryError - 因为副本的jvm参数配置有:
-XX:+ExitOnOutOfMemoryError, 该实例的JVM(PID为1)立即退出. - 因为
pid 1进程退出, 此时pod立刻出于Terminating状态, 并且变为:Terminated - 同时, customer的SVC 负载均衡会将该副本从SVC 负载均衡中移除, 用户请求不会被分发到该节点.
- K8S检测到副本数和Deployment replicas不一致, 启动1个新的副本.
- 待新的部分Readiness Probe 探测通过, customer的SVC负载均衡将这个新的副本加入到负载均衡中, 接收用户请求.
在此过程中, 用户基本上是对后台故障"无感知"的.
当然, 要做到这些, 其实JVM参数以及启动脚本中, 还有很多细节和门道. 如: 启动脚本应该是: exec java ....$*
有机会再写文章分享.
新的疑问
上边一章, 我们解释了"为什么Java容器推荐使用ExitOnOutOfMemoryError而非HeapDumpOnOutOfMemoryError", 但是细心的小伙伴也会发现, 新的配置也会带来新的问题, 比如:
- JVM从fullgc -> OutOfMemoryError 这段时间内, 用户的体验还是会下降的, 怎么会是"故障无感知"呢?
- 用"ExitOnOutOfMemoryError"代替"HeapDumpOnOutOfMemoryError", 那我怎么定位该问题的根因并解决? 2个参数一起用不是更香么?
这些其实可以通过其他手段来解决:
- JVM从fullgc -> OutOfMemoryError 这段时间内, 用户的体验还是会下降的, 怎么会是"故障无感知"呢?
- 答: 配置合理的
Readiness Probe, 只要Readiness Probe探测失败, K8S就会自动将这个节点从SVC中摘除. 那么合理的Readiness Probe在这里指的就是应用不可用时,Readiness Probe探测必然是失败的. 所以一般不能是探测某个端口是否在监听, 而是应该是探测对应的api是否正常. 如下方. - 答: 通过Prometheus JVM Exporter + Prometheus + AlertManger, 配置合理的AlertRule. 如: "过去X时间, GC total time>5s"告警, 告警后人工介入提前处理.
- 答: 配置合理的
- 用"ExitOnOutOfMemoryError"代替"HeapDumpOnOutOfMemoryError", 那我怎么定位该问题的根因并解决? 2个参数一起用不是更香么?
- 答: 目的是为了"快速退出, 快速终结". 毕竟做HeapDump也是需要时间的, 这段时间内可能就会造成体验的下降. 所以, 只有"ExitOnOutOfMemoryError", 退出地越快越好.
- 答: 至于分析问题, 可以通过其他手段分析, 如嵌入"Tracing agent"做Tracing的监控, 通过分析故障时的traces定位根因.
- 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的最优参数, 在今天来看, 并不一定仍是最优解.
三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.
为什么 java 容器推荐使用 ExitOnOutOfMemoryError 而非 HeapDumpOnOutOfMemoryError ?的更多相关文章
- Java 容器相关知识全面总结
Java实用类库提供了一套相当完整的容器来帮助我们解决很多具体问题.因为我本身是一名Android开发者,包括我在内很多安卓开发,最拿手的就是ListView(RecycleView)+BaseAda ...
- 工作随笔—Java容器基础知识分享(持有对象)
1. 概述 通常,程序总是运行时才知道的根据某些条件去创建新对象.在此之前,不会知道所需对象的数量,甚至不知道确切的类型,为解决这个普遍的编程问题:需要在任意时刻和任意位置创建任意数量的对象,所以,就 ...
- Java容器--2021面试题系列教程(附答案解析)--大白话解读--JavaPub版本
Java容器--2021面试题系列教程(附答案解析)--大白话解读--JavaPub版本 前言 序言 再高大上的框架,也需要扎实的基础才能玩转,高频面试问题更是基础中的高频实战要点. 适合阅读人群 J ...
- 【Java心得总结六】Java容器中——Collection
在[Java心得总结五]Java容器上——容器初探这篇博文中,我对Java容器类库从一个整体的偏向于宏观的角度初步认识了Java容器类库.而在这篇博文中,我想着重对容器类库中的Collection容器 ...
- Java 容器(list, set, map)
java容器类库的简化图: (虚线框表示接口, 实线框表示普通的类, 空心箭头表示特定的类实现了接口, 实心箭头表示某个类可以生成箭头所指的类对象) 继承Collection的主要有Set 和 Lis ...
- Java - 容器详解
一.ArrayList 长度可变数组,类似于c++ STL中的vector. 元素以线性方式连续存储,内部允许存放重复元素. 允许对元素进行随机的快速访问,但是向ArrayList中插入和删除元素的速 ...
- java容器---集合总结
思考为什么要引入容器这个概念? Java有多种方式保存对象(应该是对象的引用),例如使用数组时保存一组对象中的最有效的方式,如果你想保存一组基本类型的数据,也推荐使用这种方式,但大家知道数组是具有固定 ...
- java 书籍推荐 JavaEE程序员必读图书大推荐
java 书籍推荐 JavaEE程序员必读图书大推荐 转自:http://www.cnblogs.com/xlwmin/articles/2192775.html 下面是我根据多年的阅读和实践经验,给 ...
- java容器的理解(collection)
容器类(Conllection)对于一个开发者来说是最强大的工具之一,可以大幅提高编程能力.容器是一个将多个元素组合到一个单元的对象,是代表一组对象的对象,容器中的对象成为它的元素. 容器适用于处理各 ...
- Java面试题-Java容器
一.Java容器分类 Java容器划分为两个概念Collection.Map Collection: 一个独立元素的序列,这些元素都服从一条或多条规则.List必须按照插入的顺序保存元素,不关心是否重 ...
随机推荐
- dotnet 用 SourceGenerator 源代码生成技术实现中文编程语言
相信有很多伙伴都很喜欢自己造编程语言,在有现代的很多工具链的帮助下,实现一门编程语言,似乎已不是一件十分困难的事情.我利用 SourceGenerator 源代码生成技术实现了一个简易的中文编程语言, ...
- Linux实战笔记__Centos7上搭建DVWA网站(基于宝塔)
安装宝塔套件 宝塔官网有远程安装代码https://www.bt.cn/bbs/thread-19376-1-1.html 下载DVWA并上传至/www/wwwroot目录 下载地址: 配置数据库连接 ...
- 【JavaWeb】学习笔记——JSP
概念 全称:Java Server Pages, Java服务端页面 描述:一种动态的网页技术,可以在其中定义HTML.JS.CSS等静态内容,以及Java代码的动态内容 说明:JSP = HTML ...
- JS中的键盘Keycode
常用的keycode 组合键 if ((window.event.ctrlKey)&&(window.event.keyCode==49)) alert("您按下了CTRL+ ...
- Vue中常用的几种传值方式
Vue中常用的几种传值方式 1. 父传子 父传子的实现方式就是通过props属性,子组件通过props属性接收从父组件传过来的值,而父组件传值的时候使用 v-bind 将子组件中预留的变量名绑定为da ...
- 二十二、Pod存储之volume
Pod 的存储之volume 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题.首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失--容器以干净的状 ...
- Linux系统命令基础
Linux系统命令基础 前面咱们已经成功安装了Linux系统--centos7,那么现在奔向Linux命令行的世界. Linux命令格式 1.一般情况下,[参数]是可选的,一些情况下[文件或路径]也是 ...
- [VUE]报错: No Babel config file detected for
在使用vue脚手架创建的项目中,项目中每个文件的第一行都会有红色波浪线. 解决方法:在项目文件中找到package.json文件,在parserOptions里添加"requireConfi ...
- Agda学习笔记1
目录 Agda学习笔记1 快捷键 refl Natural Number 自然数集合 operations rewrite cong 加法结合律 加法交换律 乘法分配律 比较大小 衍生的一些证明 be ...
- 上下文管理器 context managet
定义:实现了上下文管理协议的对象,主要用于保存和恢复各种全局状态,关闭文件等,它本身就是一种装饰器. with语句 with语句就是为支持上下文管理器而存在的