当前位置:Java -> 优化机器人应用程序的性能
在这篇文章中,我们想分享一下我们在优化一个控制仓库机器人的Java应用程序时所获得的实际经验。这个应用程序会给仓库中的机器人下达指令,告诉它们应该执行什么动作。根据这些指令,机器人在仓库里完成工作。偶尔情况下,这个应用程序会变慢,不给机器人下达指令。如果机器人没有从应用程序那里收到指令,它们就会开始自行决策,导致它们的行为出现退化,进而影响了仓库的交付和发货。
开始排查Java应用程序性能问题的最佳方法是研究它的垃圾回收性能。尤其是当应用程序出现减速时更为重要。我们拿到了这个应用程序的垃圾回收日志文件,并将它上传到 GCeasy 工具(注: 垃圾回收日志包含了大量重要的统计数据,这些数据大多数监控工具都没有报告,并且几乎不会对应用程序造成任何额外开销。因此,最佳实践是在所有生产实例上启用垃圾回收日志)。该工具分析了垃圾回收日志,瞬间生成了 这份富有见地的GC日志分析报告。
这个工具报告了各种有趣的指标和图表。报告中的垃圾回收暂停时间图对我们的讨论最有兴趣。以下是该图:
每当垃圾回收事件发生时,它会暂停整个应用程序。在那个暂停期间,所有的客户交易都不会被处理。所有进行中的交易也会被暂停。从上图可以看出,于上午11:35,在高峰流量时段,垃圾回收事件导致整个应用程序暂停了329秒(即5分钟又29秒)。这意味着在整个5分钟以上的时间内,所有的机器人都没有收到该应用程序的任何指令。它们会自主决策,对业务造成干扰。
导致长时间的垃圾回收暂停有两个主要原因:
这是一篇博客文章,重点介绍了减少长时间垃圾回收暂停的潜在解决方案。我们正在考虑一些解决方案来解决这个长时间的GC暂停。
减小应用程序的堆大小是一个潜在解决方案。然而,这个单体应用程序的对象创建速率非常高,减小堆大小有可能影响应用程序的响应性。只有在应用程序的内存消耗能够得到减少时,才可以减小堆大小,这需要对应用程序代码进行重构。这个单体应用程序的重构正在进行中,正在被拆分并以更小的堆大小重写为微服务。然而,这个应用程序的重构预计将在6-9个月后上线。因此,客户在这之前有些犹豫减小堆大小。
另外一个解决方案是迁移,不再使用CMS GC算法。无论CMS GC算法的性能如何,自Java 9以来,该算法已被弃用,并将在Java 14中被永久移除。如果我们想要远离CMS GC算法,我们有哪些替代选择?以下是OpenJDK中可用的备选GC算法:
串行GC算法仅适用于单线程、桌面类型的应用程序。由于这个应用程序有多个并发线程,对象创建速率非常快,我们排除了串行GC算法。由于该应用程序运行在Java 8上,我们排除了ZGC和Shenandoah GC,因为它们只有在Java 17+上才是稳定的。因此,我们只能选择使用并行GC或G1 GC。
我们在性能实验室中模拟了生产流量,并根据最佳GC调优实践,对并行GC和G1 GC算法进行了实验。我们发现,并行GC的暂停时间不如CMS GC糟糕,但也不如G1 GC好。因此,我们最终决定将CMS GC算法切换为G1 GC算法。这是在使用G1 GC算法时在性能实验室中对这个机器人应用程序的GC日志分析报告,以下是使用G1 GC算法时的GC暂停时长图:
从图中可以看出,最大的GC暂停时间为2.17秒,这是与5分29秒相比显著的改进。而平均GC暂停时间仅为198毫秒,远比该应用程序的CMS GC算法好。
切换到G1 GC算法后,应用程序的随机减速完全停止了。因此,无需进行重大架构更改,无需重构代码,也无需进行任何JDK/基础设施升级,只需通过调整JVM中的GC参数,我们就能为这个机器人应用程序的性能带来显著优化。
推荐阅读: 阿里巴巴面经(53)
本文链接: 优化机器人应用程序的性能