Netflix 升级至 Java 21 并采用新特性
Netflix 长期采用 Java 技术,近期升级至 Java 21,并利用其中的新特性来提升其庞大微服务集群的性能。这些新特性包括 Generational ZGC(JEP 439)和 虚拟线程(JEP 444)。
虚拟线程的挑战
尽管虚拟线程在高吞吐量并发应用中表现出早期潜力,但在实际应用中,Netflix 遇到了独特的问题。在 Netflix 技术博客的一篇文章中,JVM 生态系统团队分享了他们在使用虚拟线程时的经验,特别是服务出现超时和挂起实例的问题。
问题描述
在基于 SpringBoot 的应用中,Netflix 工程师观察到,运行在 Java 21 和 SpringBoot 3 上的服务出现间歇性超时和无响应实例。尽管 JVM 实例仍在运行,但已停止处理流量,这表现为大量套接字处于 closeWait 状态。
根本原因分析
初步诊断表明,虚拟线程与阻塞操作和操作系统线程可用性之间的交互导致了类似死锁的情况。使用 jcmd Thread.dump_to_file 命令,团队发现了数千个“空白”虚拟线程,这些线程已创建但尚未运行。问题源于 Tomcat 的请求处理机制,新创建的虚拟线程由于操作系统线程不可用而无法被调度。
死锁场景
分析显示,Tomcat 的虚拟线程执行器为每个请求创建线程,但这些线程因等待锁而停滞。具体来说,线程由于同步块内的阻塞操作而被固定到操作系统线程,而可用的操作系统线程数量有限,导致了死锁。
解决方案
Netflix 的 JVM 生态系统团队使用堆转储检查锁的状态,并确认没有线程拥有该锁,但等待该锁的线程无法继续执行。团队识别出根本原因,并开发了可重现的测试用例,以防止未来出现类似问题。
虚拟线程的潜力与挑战
尽管 Java 21 中的虚拟线程在减少开销方面显示出潜力,但此案例强调了理解其与现有线程模型和锁定机制交互的重要性。InfoQ 上的一篇案例研究也深入探讨了虚拟线程的实践挑战和好处,特别是在涉及高并发工作负载的场景中。
Generational ZGC 的作用
除了虚拟线程,Netflix 还采用了 Generational ZGC 来优化系统性能。ZGC 能够在堆大小增长时保持低暂停时间,显著减少了垃圾回收开销,提高了应用的响应性。
Netflix 的监控系统
Netflix 的 Atlas Streaming Eval 平台在识别和诊断这些问题中发挥了关键作用。该系统设计用于改进实时监控和警报,帮助团队捕捉问题状态并提供关键数据用于事后分析。
未来展望
尽管面临挑战,Netflix 对虚拟线程的未来持乐观态度,并期待在未来的 Java 版本中进一步改进,特别是在解决与锁定原语的集成挑战方面。此案例研究为性能工程师和开发人员在探索虚拟线程时提供了宝贵的参考。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。