知识卡片

GC问题排查的核心洞察:常规调优手段全部失败时,很可能不是GC策略问题,而是应用的Bug

普通读书笔记卡

内容

百姓网在Elasticsearch从1.x滚动升级到2.x的过程中,频繁遇到严重的GC问题,几乎导致整个升级失败:某些节点CPU使用率突然飙升到100%并长期保持,节点因为长期无响应被集群踢出,即使重新加入也很快又陷入同样的100%CPU、不死不活的状态;查日志发现并没有出现OOM,但GC问题很明显——运行几次CMS GC之后触发Full GC,Heap使用率长期保持在90%左右,进入了GC死循环。团队最初的排查方向完全聚焦在GC本身:尝试了GC调优、切换CMS和G1策略、调整heap size和heap NewSize、调整线程池各项参数、调整过大的query size——这些针对”GC策略”和”资源配置”的常规调优手段全部尝试过,却全部失败,问题依然存在。真正的转折点是团队意识到一条重要的经验:”当我们遇到JVM GC时,很可能并非GC策略本身问题,而是应用的Bug”——这句话促使团队把排查方向从”如何调好GC参数”彻底转移到”应用层面到底做错了什么导致GC压力异常”,最终真正定位到问题根源的两个”深坑”,都不是GC参数配置问题,而是应用层面的查询写法本身触发了不合理的内存分配模式(详见后续关于filtered query和aggregations histogram的具体案例)。这个案例给出了一条排查性能问题时极具价值的元认知:当某一类症状(这里是GC)表现得很突出、很容易第一时间锁定为问题所在时,人很自然地会把全部精力投入到”优化这个症状本身”(调GC参数);但如果针对这个症状本身的常规调优手段反复尝试都无效,这本身就是一个强烈的信号,说明真正的病灶可能根本不在这个症状所在的层面(GC/JVM配置),而在更上层的应用逻辑里——GC压力大很可能只是应用层某种不合理的内存分配模式表现出来的一个”果”,而不是问题本身的”因”,一旦常规调优反复碰壁,就应该考虑把排查范围从”调参数”切换到”审查具体是什么业务查询/逻辑制造了这种异常的内存压力”。

参考来源

- 位置:《高可用架构(第1卷)》第6章《大数据与数据库》"6.3 百姓网Elasticsearch2.x升级之路"节,"6.3.2 升级之路"(源文件:_epub-src/OEBPS/Text/Chapter6_3_3.xhtml) - 结论依据:原文说明"首先我们尝试了进行GC调优、CMS、G1、调整 heap size、heap NEW size等方法,各种策略均告失败……一开始我们判断是GC问题,故而一直进行GC调优,但未果。当我们遇到JVM GC时,很可能并非GC策略本身问题,而是应用的Bug",直接支撑本卡片结论。 - 原始内容:首先我们尝试了进行GC调优、CMS、G1、调整 heap size、heap NEW size等方法,各种策略均告失败……一开始我们判断是GC问题,故而一直进行GC调优,但未果。当我们遇到JVM GC时,很可能并非GC策略本身问题,而是应用的Bug。