当前升级JDK的动力实际上主要来自三项:ZGC、虚拟线程、衍生生态
1.总体分析
一下对JDK高版本主要特性做一个总览分析
ZGC
优点:ZGC基本消除了GC带来的延迟,并且对大对象有更好的处理
不足:ZGC吞吐量比不上G1,即便分代ZGC吞吐量有了很大提升,但与G1依然有一定差距。
虚拟线程
优点:适用IO密集型应用,一方面可以提高系统性能,另一方面可以极大消除线程带来的内存压力
不足:在目前JDK21的版本中,虚拟线程存在的坑还比较多,个人不建议在可靠性要求较高的应用上使用
衍生生态
许多Java生态的框架都基于高版本jdk开发,并不再维护低JDK版本。如果想要探索基于高版本的框架,那么升级JDK也是势在必行的了。
2.什么应用适合升级JDK?
| 目标 | 适用应用 | 具体版本 | 风险 |
|---|---|---|---|
| ZGC |
|
如果对吞吐量追求不高,可以考虑JDK17以上; 如果对吞吐量有较高要求,需要升级JDK21,并且开启分代特性。 |
分代ZGC并没有完全成熟,经过充分的验证后才可上线 |
| 虚拟线程 | IO密集型应用 都可以升级(文件IO除外) | JDK21 | |
| 衍生生态 | 需要按照自己实际的调研进行升级考虑,例如S pring Modulith等 | —— | —— |
3. 实际收益
分代ZGC
我们对一个缓存型服务升级了JDK21,并使用了分代ZGC,在没有明显观察到资源占用提高的前提下解决了GC带来的长尾问题。
我们在3.28下午发布了一个集群,这是这个集群发布前后的长尾响应耗时情况
这是与JDK11 G1集群的对比,黄线是JDK11+G1,绿线是JDK21+ZGC
另外也可以参考Netflix这篇很好的文章 https://netflixtechblog.com/bending-pause-times-to-your-will-with-generational-zgc-256629c9386b
虚拟线程
我们在一个 IO 密集型服务进行了全面jdk21升级,并进行了虚拟线程灰度验证。
下图验证时对比非虚拟线程,平台线程数从2000降低到300+(7.19-7.26期间是由于某个依赖组件不支持虚拟线程,某个依赖组件里面开了300个平台线程,7.26后某个依赖组件替换为虚拟线程池)
对于虚拟线程,我们单独开了一个集群用于灰度(下图vt 集群)
下图中黄色线是JDK21集群,绿色为JDK21+虚拟线程集群
| 非虚拟线程(jdk21) p95 | 虚拟线程(jdk21) p95 | 降幅 | |
|---|---|---|---|
| 列表查询 | 284 | 239 | 19% |
| 详情查询 | 589 | 493 | 16.3% |
加上升级jdk21本身带来的优化,对比jdk11的应用,虚拟线程+jdk21带来的p95降幅大概在20%
TODO:
使用虚拟线程后,不再需要像传统线程池一样进行参数调整,例如线程数,队列大小等等。
以前使用的线程池似乎会在某些场景下存在任务积压的问题,导致耗时大面积上升,切换后我们会进行压测,预期能将单机流量提升3倍以上。