【转帖】SRE 高延迟问题的罪魁祸首 System.gc()
https://www.infoq.cn/article/lXTRgYb9ecVBu*72fT7O jstact -gccause pid 3000 30
01 案例一:
某日,支付平台的开发人员找到 SRE,需要 SRE 帮助解决一个棘手的问题。他们发现一个调用第三方支付接口的应用里面,偶尔出现请求超时的情况。第三方平台保证他们的服务 99%在 10 秒内完成,算上网络传输时间,15 秒足够了,尽管支付平台设置的超时时间是 30 秒,但还是发生了超时的情况。
从最近一周日志的数据来看,大概每天出现 15~40 次超时问题。发生的时间也没有什么大致规律,有时同时出现 2~3 次,有时过 2 个小时才又出现一次。尽管客户只要重试几乎全部成功,并且这种请求错误出现的次数相对于总请求数比例极低,可这确实影响部分用户的支付体验。
出现的总数量虽相对不高,但影响用户体验的问题必须是大问题。
支付平台的小伙伴先是和这个外部支付公司联系,根据我们提供的业务 ID,该公司确认他们那边都是很快完成了支付,不存在超时的现象。
那么还有一个可能是中间的网络问题,网络先是通过我们的内网,然后是互联网,最后是他们的内网,这中间任何一步都有可能出现网络的抖动,导致我们的业务超时。
可是为什么又每天出现这么多次呢? 因为网络问题涉及外网,并没有那么容易查清楚,并且每天分布的时间点并没有什么规律,所以支付平台的小伙伴转而找到 SRE 寻求帮助。
SRE 拿到这个问题之后,也感觉很棘手。这种超时问题,我们一般分为三段:
首先是服务提供者,它的处理时间变长,直接导致超时,这个问题中第三方已经确认他们并没有超时。
其次是中间的网络传输,这个问题中我们又跨越 3 段网络:我们的内网,互联网和服务提供商的网络。任何一段出问题,都会导致问题超时,并且这里面有很多是我们很难拿到数据去诊断的。
再次是服务客户端,我们的代码里面偶尔也会出现使程序变慢的地方,但这也是我们最不容易去怀疑的地方,因为它是我们自己写的代码。
鉴于每天出现的数量和网络的不确定性,SRE 决定先排除我们这端代码的问题。这个应用有几十台服务器分布在三个数据中心,每个数据中心的服务器都出现过这种超时问题。平时这个业务都是在 5 秒左右完成,但发生超时的时候等待 30 秒都无法完成。
SRE 先是找到一个具体的错误日志,然后观察了那台服务器的各种监控指标,发现那台服务器的 GC 开销在出错的时间点左右有明显增高,初步怀疑是 GC 导致的变慢。
继而查看当时的 verbose GC 日志,确认那个时间点确实有 Full GC 发生,并且 Full GC 时间超过 30 秒。不过发生的时间点上堆内存和永久代内存都有足够空闲,于是怀疑是 System.gc()导致的问题。
又查看其它几个出错的例子,发现一样的问题。查看更长时间的 verbose GC 日志,发现这种 Full GC 对于每一台机器都是每隔 24 小时出现一次。与服务启动成功时间对比,发现第一次发生的时间点正是服务刚启动之后的时间点,之后每天这个时间点再来一次。
开发人员搜索并确认了他们的代码中并没有明确的 System.gc()调用,所以只能怀疑某个依赖库中存在这个调用。虽然确认的过程稍显复杂,但是在 JVM 启动参数中添加-XX:+DisableExplicitGC 后终于彻底解决了这个问题。
02 案例二:
某日,监控平台上突然跳出一个新的报警,一个应用的 CPU 使用率突然达到了 60%以上。SRE 查看这个应用的历史记录,发现之前它的 CPU 使用率基本在 5%以下。智能的云监控平台已经检测到这个问题,并且已经尝试通过替换新机器的方式帮它去修复了。
SRE 并没有发现这个应用最近有什么新的代码部署,也没有发现最近有新的请求 URL 进入。联系开发人员,他们说可能上游最近有变动,发过来的请求内部有不同的参数,导致可能走不同的代码路径。
查看这个应用的监控指标数据,发现这个应用的 GC 开销明显提高,是 GC 导致 JVM CPU 开销增加。于是 SRE 查看了它的 verbose GC 日志,具体如图 1 所示:
图 1(点击可查看大图)
我们看到堆空间有大量空闲,却频繁地在做 Full GC。从图 2 的原始日志可以看到,永久代也有大量空闲内存。
图 2(点击可查看大图)
于是我们通过 jstat 命令查看了做 Full GC 的原因:
图 3(点击可查看大图)
原来也是 System.gc()方法导致的。也就是说新的代码路径里面有 System.gc()的调用。和上面的问题一样,加上**-XX:+DisableExplicitGC 参数**后就修复了这个问题。
03 如何排查及修复
上面两个案例都是有人在代码中明确调用 System.gc()导致的问题,并且都通过添加 JVM 启动参数-XX:+DisableExplicitGC 得以解决。
那么如果真的想要从代码层面修复这个问题,怎么才能找到这段代码呢?
通常,如果这个调用发生在我们可控的源代码里,基本通过全文搜索或者借助 IDE 里面的方法调用查询,都能找到。
如果这个 System.gc()调用在某个依赖包里面,如何才能找出来呢,这经常是比较麻烦的一步。这里介绍两个方法:
如果这个应用可以本地调试,只要开启调试(debug)模式,然后在 System.gc()方法上设置断点,那么一旦运行到这一步,调试视图就会立马告诉你。
使用 FindBugs 工具,它能分析工程里面的源代码和依赖包,通过 DM_GC 这个规则就能查找出调用点。具体见图 4:
图 4(点击可查看大图)
04 System.gc()存在的必要性
System.gc()方法一旦被调用并被执行,它将是一次 Full GC。Full GC 对于绝大多数 Hotspot JVM 实现里面已有的 GC 算法而言,将是一次相对比较长的全局停顿(stop-the-world)。
在一些对时延要求比较高的服务上,这将造成一定程度的不能满足 SLA。甚至可能在瞬间因为客户端的超时,带来更多不必要的重试请求。正常情况下,JVM 都有自适应算法去判断什么时候需要做一次 GC,并且尽力避免 Full GC,所以大多数情况下,不需要编程人员调用 System.gc()方法。
这并非说这个方法没有用处,在以下场景,这个方法能带来一些有益的效果:
1. 服务启动并初始化完成,在没有提供服务之前调用 System.gc()。这样可以回收掉启动过程中一些未来没必要存在的对象,大幅提高可用堆的数量,并且把一些对象从年轻代直接移到了老年代,不再需要经过多次在 Survival 空间来回移动才最终移到老年代。
2. 在做 heap dump 之前。这样回收掉一些已经没有被引用的对象,减少 heap 中没必要分析的对象。
3. 微观测试(microbenchmark)之前。减小由于测试当中可能出现 GC 过程引起的测试结果不正确。
05 总结
System.gc()作为 Java 提供的一个方法,在如今 JVM 已经很智能的情况下,大多数时候已经不再需要我们明确去调用它。一旦发生了延迟较长的情况,可以把这个方法的调用作为一个怀疑的对象。通过一些具体的方法能够找到调用的点并且修复这个问题。
本文转载自公众号 eBay 技术荟(ID:eBayTechRecruiting)。
原文链接:
【转帖】SRE 高延迟问题的罪魁祸首 System.gc()的更多相关文章
- 利用iWARP/RDMA解决以太网高延迟
导读:“iWARP能够带来超低延迟.”据介绍,RDMA,即远程直接内存访问提供了应用程序到应用程序的直接通信能力,这也就意味着,应用将跳过操作系统,实现远程内存应用程序的访问 关键词: iWARP 低 ...
- 当 Redis 发生高延迟时,到底发生了什么
Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多.但是 Redis 也会发生延迟时,这是就需要我们对其产生原因有深刻的了解,以便于快速排查问题,解 ...
- [转帖]瀚高数据库创建uuid的方法
使用syssso登录,并执行下列语句 highgo=> select set_secure_level('off'); set_secure_level -------------------- ...
- VMThread占CPU高基本上是JVM在频繁GC导致,原因基本上是冰法下短时间内创建了大量对象堆积造成频繁GC。
今天线上一个java进程cpu负载100%.按以下步骤查出原因. 1.执行top -c命令,找到cpu最高的进程的id 2.执行top -H -p pid,这个命令就能显示刚刚找到的进程的所有线程的资 ...
- 【J2EE性能分析篇】JVM参数对J2EE性能优化的影响
一切J2EE应用都是基于JVM的,那么对于JVM的设置和监控,成为J2EE应用程序性能分析和性能优化的必然手段.今天Sincky和大家交流该话题.这里以Tomcat环境为例,其它WEB服务器如Jbos ...
- 阅读《Effective Java》每条tips的理解和总结(1)
<Effective Java>这本书的结构是90来条tips,有长有短,每条tip都值的学习.这里根据对书中每条tip的理解做简短的总结,方便日后回顾.持续更新~ 1. 考虑用静态方法代 ...
- 【C# .Net GC】后台垃圾回收
在后台垃圾回收 (GC) 中,在进行第 2 代回收的过程中,将会根据需要收集暂时代(第 0 代和第 1 代). 后台垃圾回收是在一个或多个专用线程上执行的,具体取决于它是后台还是服务器 GC,它只适用 ...
- 高吞吐低延迟Java应用的垃圾回收优化
高吞吐低延迟Java应用的垃圾回收优化 高性能应用构成了现代网络的支柱.LinkedIn有许多内部高吞吐量服务来满足每秒数千次的用户请求.要优化用户体验,低延迟地响应这些请求非常重要. 比如说,用户经 ...
- 高吞吐、低延迟 Java 应用的 GC 优化实践
本篇原文作者是 LinkedIn 的 Swapnil Ghike,这篇文章讲述了 LinkedIn 的 Feed 产品的 GC 优化过程,虽然文章写作于 April 8, 2014,但其中的很多内容和 ...
- Java编写高质量代码改善程序的151个建议
第一章 Java开发中通用的方法和准则 建议1:不要在常量和变量中出现易混淆的字母: (i.l.1:o.0等). 建议2:莫让常量蜕变成变量: (代码运行工程中不要改变常量值). 建议3:三元操作符 ...
随机推荐
- 第四部分_Shell脚本数组和其他变量
数组定义 ㈠ 数组分类 普通数组:只能使用整数作为数组索引(元素的下标) 关联数组:可以使用字符串作为数组索引(元素的下标) ㈡ 普通数组定义 可以切片 一次赋予一个值 #数组名[索引下标]=值 ar ...
- 创新 = 颠覆?AI创新如何做大蛋糕
本文分享自华为云社区<创新 = 颠覆?AI创新如何做大蛋糕>,作者: 华为云PaaS服务小智 . 最近随着AI的风靡,各行各业都充斥着近乎疯狂的言论,"AI必将替代一切" ...
- 解读革命性容器集群CCE Turbo:计算、网络、调度全方位加速
摘要:CCE Turbo是华为云推出的一款革命性容器集群. 5月31日,在华为云Techwave云基础设施技术专题日上,华为云容器批量计算首席架构师马达对CCE Turbo的技术内幕进行了深度解读,C ...
- [BitSail] Connector开发详解系列三:SourceReader
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 Source Connector 本文将主要介绍负责数据读取的组件SourceReader: SourceRead ...
- 火山引擎DataLeap数据质量动态探查及相关前端实现
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 需求背景 火山引擎DataLeap数据探查上线之前,数据验证都是通过写SQL方式进行查询的,从编写SQL,到解析运 ...
- Word 文档怎么保留修改前和修改后的内容--审阅 修订
如果启用了修订内容后,对文档的内容进行了相关的修改后.则文档可以同时显示被修改的内容和修改后的内容.下面,本文通过举例具体介绍如何使用修订功能. 点击选中文档内容,然后依次点击[审阅]-[修订]-[修 ...
- 使用 BLIP-2 零样本“图生文”
本文将介绍来自 Salesforce 研究院的 BLIP-2 模型,它支持一整套最先进的视觉语言模型,且已集成入 Transformers. 我们将向你展示如何将其用于图像字幕生成.有提示图像字幕生成 ...
- Python 网络舆情分析系统,舆论可视化界面
1 简介 舆情管理系统,这不仅仅可以帮助当地的管理人员迅速的排查跟本地有关的负面言论,还可以避免网民因为本身意识不到位而评论或发布一些不好的观点的情况,最终的目的就是帮助社会更好的发展. 2 技术栈 ...
- 3 分钟看完 NVIDIA GPU 架构及演进
近期随着 AI 市场的爆发式增长,作为 AI 背后技术的核心之一 GPU(图形处理器)的价格也水涨船高.GPU 在人工智能中发挥着巨大的重要,特别是在计算和数据处理方面.目前生产 GPU 主流厂商其实 ...
- 对于 CDN 的多元理解
这是二狗子为数不多的创业故事. 那时二狗子还是一名高中生,学校是封闭式管理.由于二狗子总忍不住上课吃零食,他便每周一都会背着一麻袋零食来上学. 这上课吃零食行为,不知不觉诱惑到了周围的同学.大家纷纷向 ...