JVM GC 性能测试(二):递增流量
JVM GC 性能测试系列:
在上一篇文章 JVM GC 性能测试(一):相同流量 中,D瓜哥使用一个总量请求对所有分组的所有机器进行性能测试。但是,经过测试发现了一个问题,同时产生了另外一个问题,有两个问题没有得到很好的解答:
由于服务响应时长直接关系到服务调用次数,当某一台机器出现问题时,整体调用次数就会急剧下降,调用次数加不上去。一个机器出问题,所有机器的访问量就上不去了。这是测试中发现的一个问题。当然,这属于测试工具的问题,别不是 GC 的问题。但是,也影响到我们的压测,也需要解决。
上次测试,这是针对某一个指定服务调用量进行性能测试,那么,无法确定每个 GC 能支撑的极限调用峰值。另外,在极限峰值和超极限峰值的情况下,各个 GC 的表现如何?这个也有待验证。
针对上述两个问题,设计了本次测试。测试方法如下:
各个分组使用一套相同的流量策略:
各个分组几乎同时开始执行测试任务;
调用量从低到高,以此同时使用相关的调用量进行测试;
除最开始预热阶段的调用量外,后续每个调用量都持续进行十分钟的测试。
针对每个 GC 分组单独设定一套调用发量程序,这个保证各个 GC 分组直接不相互影响。
最后,再分析调用量相同时段的各个 GC 表现,就可以看到各个 GC 的极限峰值。
为了保留更多细节,本文所有截图都是在 34 吋带鱼屏下,使用全屏模式展示并截图的。如果看不清楚,可以右击在新页面打开图片来查看。 |
具体流量及时间段:
750, 23:14:30 ~ 23:19:30
800, 23:19:30 ~ 23:29:30
850, 23:29:30 ~ 23:39:30
900, 23:39:30 ~ 23:49:30
950, 23:49:30 ~ 23:59:30
1000,23:59:30 ~ 00:09:30
1050,00:09:30 ~ 00:19:30
1100,00:19:30 ~ 00:29:30
这里的流量是单台服务器的测试接口接受到的调用量。
一言以蔽之
J21-G1 的极限峰值最高,能支撑到 1100+ QPS;其次是 J21-Gen-ZGC,大约可以支持 1000 QPS(挑食,某些机器会出现 CPU 使用率过高的问题),比 J21-G1 降低了 10%。
在 900 QPS 以下,从 TP999 的数据来看,J21-Gen-ZGC 耗时更短,响应性更好;超过 1000 QPS 时,则 J21-G1 更稳定,耗时最短。
1. 服务调用监控数据
监控服务调用的相关数据,这是对于用户来说,感知最强烈的相关数据,也是直接关系到服务质量的数据。
1.1. 服务调用次数
从调用次数上来看,J8-G1 最早开始失守,结合下面 服务调用耗时 来看,应该是 某台机器除了问题,否则 J8-G1 不会在 TP999 表现最差的情况下,TP99 的表现反而变现不错。
紧随其后,以此是 J21-ZGC、J21-Gen-ZGC、J17-ZGC 的表现开始拉胯。
在极限峰值下,J21-Gen-ZGC 的表现又反超了 J17-ZGC;由此可以看出,在极限情况下,J21-Gen-ZGC 的表现更值得信赖。
J21-G1 变现一直非常稳定,甚至没有达到它的峰值。
1.2. 服务调用耗时
J8-G1 在 TP999 表现最差,但是在 TP99 的表现反而稳居第二。应该是某个机器有问题,整体表现是可以的。
从 TP999 来看,表现最好的是 J21-G1,其次是 J21-Gen-ZGC。
1.2.1. TP999
1.2.2. TP99
1.2.3. TP90
1.2.4. 平均耗时
1.2.5. 最大耗时
1.3. 每台机器的调用次数及耗时
点击查看机器分组详情
从截图上来看,“J21-Gen-ZGC 和 J21-G1” 这组机器稳定性明显比 “J21-ZGC 、 J17-ZGC 和 J8-G1” 这组要好:
剧烈抖动出现的更晚;
在最高峰值,前者依然有机器支持高流量访问,而后者都已经全部沦陷,只有少量机器支持起降配的访问量。
看 TP99 图表,去掉了个别剧烈抖动的点,前者从 00:10 开始(也就是 QPS 已经到 1050 后),才有一半机器调用耗时过高;而后者,早早就有大量机器开始剧烈抖动。
1.3.1. TP999 及调用次数
1.3.2. TP99 及调用次数
2. JVM 监控
2.1. CPU
单独从 CPU 使用率角度来看:
J21-ZGC 和 J17-ZGC 早早就把 CPU 干到了 90%+,而这个时候 QPS 只有 750。
J21-G1 一直非常稳定,跟随 QPS 的提升,CPU 使用率也稳步上升;而 J21-Gen-ZGC 则更早的把 CPU 使用率打到接近 100%(时间是:00:00,QPS:1000)。J21-G1 比 J21-Gen-ZGC 的稳定性好很多。
2.2. Young GC
关于 Young GC 的说明,D瓜哥在 JVM GC 性能测试(一):相同流量:Young GC 中,已经做了说明,这里就不再赘述。 |
J21-G1 的 Young GC 次数也是随 QPS 的提升,逐步上升;
J21-Gen-ZGC 在前期,Young GC 次数也是随 QPS 的提升,逐步上升;临界点在“时间是:00:00,QPS:1000”,在此之后,可能是回收速度有点力不从心,开始频繁地进行 Young GC,耗时也有大幅度增加。
2.2.1. Young GC 次数
2.2.2. Young GC 耗时
2.3. Full GC
整个过程,J21-G1 几乎没有出现 Full GC(图表里只出现了两次),有些让人吃惊。
对比之下,J8-G1 却出现了频繁的 Full GC。
J21-Gen-ZGC 后期由于无法支撑超极限流量,所以 Full GC 反倒没有前期多了。
2.3.1. Full GC 次数
2.3.2. Full GC 耗时
2.4. Heap
2.5. 非堆
2.6. 线程数
3. 系统监控
3.1. CPU 使用率
3.2. 内存使用率
3.3. 磁盘读写速度
3.4. 网络流入流出速率
3.5. 每个机器 CPU 使用率
3.6. 每个机器系统负载
揭秘
在上一篇文章 JVM GC 性能测试(一):相同流量 的“后话”一节中,D瓜哥提到了对“将 JMeter 的共享模式设置为所有线程,这样的话,每次发送请求的参数都会不一样。”这句话有了新的思考和理解,在这里做个揭秘。
D瓜哥在 JVM GC 性能对比方法 中提到,对于测试接口,最好符合线上实际运行情况,那么就会出现既依赖数据库,又依赖外部接口的情况。那么外部接口的响应变化对我们的测试 GC 的表现来看,其实属于负面影响。这里,也包含数据库的情况。所以,如果“将 JMeter 的共享模式设置为所有线程”,这样每次调用都是一个新的参数(D瓜哥这里的参数样本是700w+,循环一遍要几十分钟),虽然这样的访问情况,更加符合线上真是的访问场景,但是对我们的影响也是巨大的。
如果“将 JMeter 的共享模式设置为当前线程”,这样各个线程之间调用的参数都是一样的,最早的调用相当于给后面的调用做了预热,如果外部依赖有缓存,那么后续的调用都可以直接利用外部依赖的缓存,响应会更好,对我们的测试影响反而更小,更利于对 GC 表现的测试。所以,在这次测试中,D瓜哥就是将 JMeter 的共享模式设置为当前线程。大家有不同的意见和想法,也欢迎留言交流。
下一个问题
在 JVM GC 性能测试(一):相同流量 中,D瓜哥经过小批量测试,确定的 QPS 是 500。但是,在这次测试中,QPS 直接从 750 起步(前面使用 200、400、600 各跑了 30s 做预热),最后的 QPS 达到了 1100。所以,两个测试得出的结论是一致的。那么,在实际使用中的表现纠结如何呢?这里要打个问号。所以,接下来,D瓜哥准备将这些机器接入到上线流量,使用真是的流量来验证各个 GC 的表现,敬请期待: JVM GC 性能测试(三):真实流量。