为什么 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必须按照插入的顺序保存元素,不关心是否重 ...
随机推荐
- python 运行错误收集
目录 global全局声明错误 global全局声明错误 SyntaxError: name 'is_login' is used prior to global declaration 解决办法:g ...
- 删除数组里含有a的元素,并且将null值放在后面
想去掉里面含有a的元素,并将null放在后面.放在后面就是往后移,其他值往左移 1 public static void main(String[] args) { 2 //自定义的一个数组 3 St ...
- 通过 Github Action 实现定时推送天气预报
偶然间,看到 GitHub Actions 教程:定时发送天气邮件 - 阮一峰的网络日志 这篇文章,没错,这个正好能打发自己的折腾之心,也能通过代码给生活引入一些变化. 还是在这里简单记录一下实现过程 ...
- 闻道Go语言,6月龄必知必会
大家好,我是马甲哥, 学习新知识, 我的策略是模仿-->归纳--->举一反三, 在同程倒腾Go语言一年有余,本次记录<闻道Go语言,6月龄必知必会>,形式是同我的主力语言C#做 ...
- Spring Cloud 整合 nacos 实现动态配置中心
上一篇文章讲解了Spring Cloud 整合 nacos 实现服务注册与发现,nacos除了有服务注册与发现的功能,还有提供动态配置服务的功能.本文主要讲解Spring Cloud 整合nacos实 ...
- Typora图床上传配置:PicGo+Gitee 不完全指南
每次写Markdown都要手动传图,再复制链接到Typora里,这样比较繁琐. 设置好图床,搭配PicGo,写作时直接剪贴图片到Typora,就能实现自动上传,这样就方便很多. Gitee配置: 许多 ...
- 【单元测试】Junit 4(四)--Junit4参数化
1.0 前言 JUnit 4引入了一项名为参数化测试的新功能.参数化测试允许开发人员使用不同的值反复运行相同的测试. 1.1 参数化设置 这里我们直接上例子吧. 题目: 输入小写的字符串.如字 ...
- 手记系列之二 ----- 关于IDEA的一些使用方法经验
前言 本篇文章主要介绍的关于本人在使用IDEA的一些使用方法,一些常用设置,一些插件推荐和使用.请注意,本文特长,2w多字加上几十张图片,建议收藏观看~ 前提准备 idea官网: https://ww ...
- 论文笔记 - RETRIEVE: Coreset Selection for Efficient and Robust Semi-Supervised Learning
Motivation 虽然半监督学习减少了大量数据标注的成本,但是对计算资源的要求依然很高(无论是在训练中还是超参搜索过程中),因此提出想法:由于计算量主要集中在大量未标注的数据上,能否从未标注的数据 ...
- srcddd
目录 application assembler UserReq.go UserRsp.go dto MessageResult.go UserDTO.go services UserService. ...