最近使用wrk做服务压测时有一些思考和实验,觉得挺有意思的,在此做个记录。
测试在公司的K8S容器环境中进行。
0. 猜想
猜想一:
由于wrk压测的是http,http是串行的,故在同一个连接中,需要等待一个请求返回后再请求下一个。因而一个连接的QPS取决于平均响应时间。总的请求QPS = 1/平均响应时间 * 连接数。故想负载充分,一定要加大连接。
猜想二:
假设服务只用一个线程处理请求(或运行在一台机器上),且请求的处理是纯CPU计算,则服务能负载的最大QPS就是 1/平均响应时间,此时CPU跑满。
那么若服务运行在多核机器上,且使用多线程,且请求的处理是纯CPU计算,则服务最大能负载的QPS就是 1/平均响应时间 * 核数。
然而实际上处理请求不可能是纯CPU计算,大部分其实是网络等待时间。此时等待的线程会让出CPU时间。所以服务最大能负载的QPS会大于 1/平均响应时间 * 核数。
总结:
1/平均响应时间 * 核数 < QPS <= 1/平均响应时间 * 连接数
转化一下就是:
核数 < QPS * 平均响应时间 <= 连接数
下面我们就来做实验验证这个猜想。被测服务是一个Java的SpringBoot服务。
0X1. 压测开始
wrk使用 2 线程,8连接压单实例的 s1,4k个商品。服务有4核。
wrk -t2 -c8 -d1000s -T10s --latency -s wrk.txt http://xxx:8080/srch-sort/v1/fine-sort
QPS 120, 平均延时64ms,TP90 80ms,TP99 95ms
平均延时 * QPS 为 7.2, 大于核数4,但刚好小于连接数8,看起来没压到瓶颈。
此时该节点的CPU已打满
wrk使用 4 线程,16连接压单实例的 s1,4k个商品。服务有4核。
QPS 105,平均延时148 ms,TP90 200ms,TP99 220ms,实例CPU打满
平均延时 * QPS 为 15,刚好小于连接数16,看起来没压好。
wrk使用 4 线程,16连接压单实例的 s1。只有2个商品。服务有4核。
QPS 1.8k, 平均延时8ms,TP90 12ms,TP99 27ms,CPU打满
平均延时 * QPS 为 15 s,刚好小于连接数16,看起来没压好。
0X2. 增加连接数
wrk使用 2 线程,32连接压单实例的 s1,4k个商品。服务有4核。
这次服务选择用 106 QPS和 300ms的平均延时来接近32. CPU压满。
所以推论三:wrk会穷尽所有的连接尽力发送,而压测的结果是响应时间和QPS形成动态均衡。QPS不会一直增长,在达到负载顶峰后会下降(抛物线)。我们压测想达到的目标就是找到抛物线的顶点。
wrk使用 2 线程,12连接压单实例的 s1,4k个商品。服务有4核。
这次是QPS 135 和 平均延时88ms,差不多是顶峰了。
0X3. 减少核数至1
wrk使用 2 线程,12连接压单实例的 s1,4k个商品。服务有1核。
这次是QPS 26,平均延时447。
乘积还是12,但性能下降了4倍以上。
0X4. 增加实例数至4
wrk使用 2 线程,12连接压单实例的 s1,4k个商品。服务有1核,4个实例。
结果是QPS 125, 平均延时 95ms。相当于1个实例4核的水平。
0X5. 使用wrk2的-R限制流量
wrk还有个进化版wrk2. (未完待续)