最近,Uber 的流量一直有指数级增长。最近的流量激增暴露了其平台中与内存相关的几个性能瓶颈:长时间的垃圾回收(GC)停顿、内存损坏、内存不足(OOM)异常和内存泄漏。在这篇精彩的文章中,Uber 工程师团队总结了自己的优化之路:他们面临着什么挑战、使用了什么工具以及在解决程序性能瓶颈时遵循了什么样的最佳实践方式。
而在优化的过程中,他们使用了我们所提供的 GCeasy 工具。在本文中,他们将介绍如何使用 GCeasy 工具来研究垃圾回收停顿时间、回收字节数等问题。作为 GCeasy 的构建者,这些是我们所乐意见到的。
本文的一部分中,Uber 工程师团队记录了他们如何识别在内存中创建大量对象的线程。他们会有一个程序线程来收集重要的 JVM 指标,并将这些指标发布到内部 TSDB 服务器以进行监控。不过意料之外的是,此线程被配置为每毫秒而不是每秒捕获 JVM 指标。也就是说,线程每秒会捕获和传输重要 JVM 指标 1000 次,而不是每秒 1 次。这就导致了 JVM 中的大量对象创建,给 JVM 带来了不必要的开销。
为了识别这个配置错误的线程,Uber 工程师团队不得不从应用程序中获取多个线程转储快照。他们必须要从这些转储文件中识别处于“RUNNABLE”状态的线程。对于这些线程,他们必须从中确定在多个线程转储快照中*持续*处于“RUNNABLE”状态的线程,这样才能发现配置错误的线程。上面提到的所有步骤都十分繁琐。而且,还需要工程师手动完成。除此之外,这样“众矢之的”的线程还有可能找错。
现代 Java 应用程序中往往会包含数百(有时是数千)个线程。从数百个线程中缩小范围,找出消耗大量 CPU 和内存的确切线程,这并不是一项简单的工作。不过,您也可以使用线程转储文件分析工具 fastThread 来快速地、准确地识别此类线程。这里有一个真实案例研究,讲解了北美一款大型交易软件开发人员使用 fastThread 工具快速识别并解决问题的过程。
Leave a Reply