1.记一次使用低版本ES Java Client偶尔查询超时问题解决过程
2.26期内存持续上升,如何排查?
3.见了鬼,我JVM的Survivor区怎么只有20M了?
4.å¦ä½äºè§£CMSçåå¾ç¢çç
记一次使用低版本ES Java Client偶尔查询超时问题解决过程
项目中ES使用版本2.4,ES JavaClient为2.4.4。一个地区项目中,查询ES接口偶现翻页超时现象,源码编辑器故事教程不确定翻页序号。
进入容器,使用top 1命令查看CPU占用,发现CPU占用较低,排除了机器配置问题。使用jstat -gcutil -t 查看GC信息,发现GC正常,各内存区占用处于正常范围,GC执行次数有限,dsmall源码排除内存不足导致超时。
问题出现在BaseFuture#get和AdapterActionFuture#actionGet位置,跟踪源码发现,BaseFuture内部Sync实现了AQS。在AQS#acquireSharedInterruptibly中调用tryAcquireShared(arg),判断是否获取共享锁。tryAcquireShared(arg)在Sync中实现,当state不为0时,返回true,state通常在ES数据获取或异常后修改。
问题定位在查询线程和等待线程的交互中,查询线程未能及时回调结果,等待线程阻塞,导致查询失败。armcc源码
为解决临时需求,增加重试机制,发现#actionGet方法支持设置超时时间。更换可设置超时API,并在捕获ElasticsearchTimeoutException时进行重试,问题得以解决。
具体为何查询线程迟迟不回调,仍在进一步排查。
期内存持续上升,如何排查?
面对内存持续上升的挑战,如何在众多进程和业务线程中找出问题根源?首先,正确选择和运用工具是关键。在Linux下,我们常借助top命令实时监控CPU和内存使用,defaultsqlsession源码top -Hp pid则能详细查看线程资源。vmstat则提供了更深入的采样分析,尤其是进程上下文切换,而pidstat则进一步到达线程层面,其参数如-p, -r和-t帮助我们深入了解内存使用。
对于Java应用,JVM内存管理尤为重要。jstat命令能够监测Java堆内存和垃圾回收情况,帮助我们理解内存分配。jstack则用于堆栈分析,有助于死锁排查。jmap不仅可以查看堆内存配置和使用,还能输出对象信息,进行详细统计和分析。sitezj源码
在复杂业务场景中,排查内存问题可能需要深入源码分析,甚至结合MAT工具进行堆内存dump。尽管工具是我们的助手,但实际问题的解决往往需要丰富的经验和个人的专业判断。记住,性能调优并非易事,它需要我们熟练运用这些工具,同时不断积累实战经验。
见了鬼,我JVM的Survivor区怎么只有M了?
某日,一位同学在群里分享了使用 jmap -heap 查看内存使用情况的截图,发现 Survivor 区占比总是在%以上,这引发了讨论。通过分析图中的信息,我们注意到 Eden、From、To 之间的比例并非默认的8:1:1,这提示我们可能存在 AdaptiveSizePolicy 的影响。使用 jinfo -flags pid 确认使用的是 JDK 1.8 的默认回收算法 UseParallelGC,并且默认开启了 AdaptiveSizePolicy。这表示每次垃圾回收(GC)后,JVM 会重新计算 Eden、From 和 To 区的大小,以适应不同的 GC 时间、吞吐量和内存占用量。在默认配置下,虽然 SurvivorRatio 的默认值是8,但年轻代三个区域的比例仍会变动,从而导致 Survivor 区的大小变化。
在讨论中,我们发现老年代的内存使用量也较高,这引起了进一步的调查。通过使用 jmap -histo 查看堆中的实例,发现有两个类的实例数量较多,分别是 ExpiringCache 和 LinkedHashMap。进一步分析发现 ExpiringCache 的构造函数初始化了一个 LinkedHashMap,这可能是问题的源头。通过分析 ExpiringCache$Entry 类和其使用场景,我们定位到问题出在使用 getCanonicalPath() 方法的类上,这会导致大量 ExpiringCache$Entry 对象进入老年代。使用 jstat -gcutil 查看 GC 情况,发现从应用启动到执行 jmap -histo 命令期间,触发了次 Full GC(FGC),耗时9.秒,平均每次 FGC 耗时约为毫秒。这表明内存管理存在优化空间。
为了解决 Survivor 区变小、老年代占比变高的问题,有几种解决方案可以考虑。一种简单的方法是不使用缓存,可以通过设置参数-Dsun.io.useCanonCaches=false 来关闭缓存。另一种方案是保持使用 UseParallelGC,显式设置 -XX:SurvivorRatio=8,以固定年轻代三个区域之间的比例。最后,可以考虑使用 CMS 垃圾回收器,因为它默认关闭 AdaptiveSizePolicy,从而提供更稳定的内存管理。
对于源码层面的理解,JDK 1.8 中的 UseParallelGC 和 AdaptiveSizePolicy 的互动主要通过参数配置来实现。当显式设置 SurvivorRatio 时,JVM 会确保这个参数在 Parallel Scavenge 回收器中生效,从而固定年轻代三个区域的比例。在 AdaptiveSizePolicy 的实现中,JVM 会在 GC 过程完成后根据预期停顿时间和实际的 GC 时间动态调整内存大小。然而,在使用 CMS 垃圾回收器时,JDK 1.8 中的逻辑会将 UseAdaptiveSizePolicy 设置为 false,这限制了 AdaptiveSizePolicy 的应用,从而影响内存管理的优化。
通过这次讨论和分析,我们不仅发现了内存管理中的问题,还学习了如何通过参数配置来优化 JVM 的垃圾回收策略。对于开发者而言,了解并合理配置这些参数可以显著提升应用的性能和稳定性。
å¦ä½äºè§£CMSçåå¾ç¢çç
PrintFLSStatisticsè¿ä¸ªåèæ¯è¾æç¨ï¼å 为CMS GCä¼æç¢çé®é¢ï¼èéçç¢ççè¶æ¥è¶ä¸¥éï¼GCæ§è½ä¼åå·®ç´å°åçFullGCï¼èFullGCæ¶STWéè¿ä¼è¶ è¿æ°ç§ï¼è¿å¯¹OLTPç³»ç»æ¥è¯´æ¯è´å½çï¼éè¿è¿ä¸ªåæ°å¯ä»¥å¨gcæ¥å¿ä¸è¾åºfree listæ¹å¼åé å ååå åç»è®¡æ åµåç¢çæ åµï¼ä»CompactibleFreeListSpaceçæè¿°å¯ç¥CMS使ç¨free liståé å å
-- æºç æèªcompactibleFreeListSpace.hppï¼
åçcompactibleFreeListSpace.cppä¸ç gc_prologue å gc_epilogue ï¼prologueçä¸ææææ¯å¼åºç½ï¼epilogueçä¸ææææ¯æ¶åºç½ï¼æ以è¿ä¸¤ä¸ªæ¹æ³å¯ä»¥ç解为gcåågcåï¼ï¼ç±ä¸¤ä¸ªæ¹æ³çå®ç°å¯ç¥ï¼å¦æJVMåæ°PrintFLSStatistics ä¸ä¸º0ï¼è´æ°ä¹å¯ä»¥ï¼ï¼é£ä¹æ¯æ¬¡GCååé½ä¼è°ç¨reportFreeListStatistics()æ¹æ³æå°åºfree listçç»è®¡ä¿¡æ¯ï¼
åçreportFreeListStatisticsçå ·ä½å®ç°ï¼å为两个é¨åæ¥çï¼
è¾åºfree listç»è®¡ä¿¡æ¯ï¼gcæ¥å¿ä¸è¾åºå 容å¦ä¸ï¼
Total Free Space:
Max Chunk Size:
Number of Blocks: 1
Av. Block Size:
Tree Height: 1
å¦æJVMåæ°ä¸ºPrintFLSStatistics 大äº1ï¼ä¾å¦-XX:PrintFLSStatistics=2ï¼é£ä¹è¿ä¼è¾åºIndexedFreeListsçç»è®¡ä¿¡æ¯ï¼ä»¥åå¦ä¸çgcæ¥å¿ï¼è½å¤ç´è§ççå°ç¢ççï¼fragçå¼è¶å¤§ç¢çåè¶ä¸¥éï¼JVMçåå§åæ¶fragçå¼ä¸º0.ï¼å³æ²¡æä»»ä½ç¢çï¼
为äºæ¥è¯¢ç¢çåçè¶æ¥è¶ä¸¥éçGCæ¥å¿ï¼ç¬è åºäºkafka 2.-1.1.1çæ¬ï¼å¯¹å ¶GCåæ°è¿è¡äºä¸äºè°æ´ï¼ä»èå¼èµ·ä¸æCMS GCï¼
æ¥ä¸æ¥åªéè¦å¯å¨ä¸ä¸ªkafka brokerï¼ç¶åå©ç¨kafkaèªå¸¦çåæµèæ¬åbrokeråé1kwæ¡æ¶æ¯ï¼æ¯æ¡æ¶æ¯ä¸ªåèï¼ï¼
bin/kafka-run-class.sh org.apache.kafka.tools.ProducerPerformance --topic topic-afei-test --num-records --record-size --throughput -1 --producer-props acks=1 bootstrap.servers=.0.1.: buffer.memory= batch.size=
ç±jstatå¯ç¥ï¼FGCé常严éï¼æ¯2så°±æ好å 次çFGCï¼
åçgcæ¥å¿ï¼kafkaé»è®¤å¼å¯äºgcæ¥å¿ï¼ä½äºï¼logs/kafkaServer-gc.log.0.currentï¼ï¼