一个HTTP接口的压力测试
潘忠显 / 2020-11-25
测试目的:
在不同网络情况下(HTTP服务器本机压测、局域网压测、广域网压测)确定接口支持的最大并发用户数,分析其性能瓶颈。
环境说明
Django版本 1.11.29
Python版本 2.7.16
wrk版本:Copyright (C) 2012 Will Glozer
服务器信息
Intel NUC10i7FNH 6核12线程 DDR4 2666 16GB
压测机信息
Macbook Quad-Core Intel Core i7 4核 8线程 16GB
网络延迟
连接情况 | round-trip min/avg/max/stddev |
---|---|
服务器 ping 服务器 | 0.042/0.045/0.058/0.007 ms |
压测机局域网 ping 服务器(Wi-Fi) | 1.789/5.264/11.558/3.654 ms |
压测机广域网 ping 服务器(Wi-Fi) | 6.126/8.914/12.447/2.022 ms |
系统内核参数
net.core.somaxconn = 128
net.ipv4.ip_local_port_range = 32768 60999
net.ipv4.tcp_tw_reuse = 1
测试工具
wrk
选择wrk是因为wrk有一个很好的特性就是能用很少的线程压出很大的并发量,通过异步网络 io 提升并发量,所以网络通信不会阻塞线程执行.
前置分析
- 将测试机与服务器分离,有效模拟真实用户情景。且将服务器部署于较干净的独立主机,有助于获得更为精准的数据。
- 本接口测试为短链接压测,考虑到过多的短连接释放会导致系统中存在大量处于“TIME_WAIT”状态的tcp端口,而默认状态下,不允许将TIME-WAIT sockets重新用于新的TCP连接,这会导致动态端口分配时出现抢占现象,进而影响性能。故在压测前,将其打开,即设置net.ipv4.tcp_tw_reuse = 1。
- 压测过程不启用过多线程,一方面系统中可允许线程数受限于ulimit -n,过多回引发“Too many open files”错误;另一方面,过多的线程数,反而会由于线程切换而影响性能。
服务器本地压测
持续时间5m
wrk线程数/连接数 | 1/1 | 1/4 | 4/4 | 12/12 | 10/100 | 1/200 | 1/400 | 1/600 | 1/1000 | 1/3000 | 1/1万 | 1/2.5万 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Django CPU | 150% | 150% | 150% | 150% | 150% | 150% | 150% | 150% | 150% | 150% | 150% | 150% |
QPS | 1423 | 1366 | 1365 | 1363 | 1361 | 1361 | 1360 | 1359 | 1357 | 1357 | 1357 | 1356 |
流量Mbps | 2.90 | 2.78 | 2.78 | 2.78 | 2.78 | 2.78 | 2.78 | 2.78 | 2.78 | 2.77 | 2.77 | 2.76 |
最大耗时ms | 9.11 | 12.63 | 11.93 | 215.52 | 1.67s | 1.67s | 1.68s | 1.86s | 1.93s | 1.87s | 1.86s | 1.74s |
90%分位耗时ms | 2.82 | 3.50 | 3.49 | 9.06 | 9.44 | 9.43 | 9.43 | 9.51 | 9.55 | 9.53 | 9.49 | 9.54 |
99%分位耗时ms | 3.84 | 4.13 | 4.23 | 9.99 | 16.97 | 11.26 | 10.78 | 217.07 | 423.66 | 217.20 | 48.74 | 217.45 |
平均耗时ms | 0.7 | 2.88 | 2.88 | 8.35 | 11.70 | 11.49 | 10.38 | 15.40 | 18.35 | 15.37 | 12.85 | 15.77 |
错误率 | 0 | 0 | 0 | 0 | 0 | 0 | 0(开始少量出现错误) | 0 | 0 | 1.2% | 3.6% | 10%(压垮) |
结论:
- 本机压测网络延迟极小<==>wrk统计1连接和多连接压测的QPS基本上相同
- 服务极限的处理能力在QPS 1400左右
- 由于Python全局解释器锁的原因,导致通常拉起的Django服务进程无法充分的利用CPU,CPU达到150%的之后不再继续上升。
- wrk CPU使用率在5%左右,没有必要使用多线程
- 比较wrk 1线程1连接情况与4线程4连接的情况,都是每个线程处理一个连接,可以认为wrk增加连接数对其本身产生的影响不大,但并发增加之后QPS下降,说明Django随着并发数增加,处理请求的能力会下降;但影响不大
- 比较wrk 4线程4连接情况与12线程12连接的情况,可以看出并发影响Django的处理能力有限,处理能力会稳定在一个水平,但最大耗时会显著增长
- 比较wrk多线程多连接情况,可以看出处理能力能稳定在同等水平,耗时相对增加,合理
- 随着连接数不断增加,当到达1线程/400连接时,开始少量出现错误;当连接数达到3000时,错误率上升至1.2%;当连接数持续增加至25000时,错误率上升至10%,系统被压垮
局域网压测
wrk线程数/连接数 | 1/1 | 1/4 | 1/10 | 1/20 | 1/50 | 1/100 |
---|---|---|---|---|---|---|
Django CPU | 125% | 125% | 125% | 125% | 125% | 125% |
QPS | 198 | 73 | 912.13 | 1392 | 1389 | 1387 |
流量Mbps | 0.4 | 0.15 | 1.8 | 2.8 | 2.83 | 2.82 |
最大耗时ms | 9.47 | 12.63 | 26.40 | 199.96 | 1.83s | 1.80s |
90%分位耗时ms | 2.94 | 3.77 | 5.04 | 10.12 | 11.27 | 11.65 |
99%分位耗时ms | 3.72 | 5.34 | 6.80 | 16.68 | 195.53 | 200.82 |
平均耗时ms | 2.38 | 2.80 | 3.72 | 9.12 | 17.29 | 18.57 |
错误率% | 0 | 0 | 0 | 0 | 0 | 0 |
结论:
- 延迟增加,不能使用低并发去压测,因为大部分耗时都将耗费在网络延迟上,无法真正压出服务器的处理能力
- 需提高并发压测
- 这里局域网压测出来的QPS相对于服务器本机压测反而略高一些,这是因为服务器本机压测时,服务与发压力相互影响。
广域网压测
wrk线程数/连接数 | 1/1 | 1/4 | 1/10 | 1/20 | 1/50 | 1/100 | 1/200 | 1/400 | 1/2000 | 1/1万 | 1/1.5万 | 1/2.5万 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Django CPU | 42% | 56% | 65% | 74% | 78% | 83% | 84% | 866.29 | 99% | 101% | 105% | 102% |
QPS | 31 | 196 | 322 | 266 | 338 | 825 | 725 | 867 | 855.1 | 773.5 | 813.8 | 792.48 |
流量Mbps | 0.06 | 0.4 | 0.66 | 0.54 | 0.69 | 1.6 | 1.5 | 1.7 | 1.7 | 1.6 | 1.6 | 1.6 |
最大耗时ms | 325.42 | 459.37 | 1.08s | 1.10s | 1.12s | 1.19s | 2.00s | 2.01s | 1.91 | 1.99 | 2.00s | 1.90s |
90%分位耗时ms | 13.74 | 13.87 | 15.62 | 18.75 | 22.84 | 52.61 | 112.39 | 100.74 | 86.81 | 116.19 | 128.3 | 103.89 |
99%分位耗时ms | 148 | 147 | 639 | 434 | 364 | 734 | 900 | 830.1 | 569.8 | 802.6 | 875.9 | 605.44 |
平均耗时ms | 15.10 | 14.15 | 27.42 | 28.78 | 23.69 | 56.71 | 98.16 | 98.34 | 70.11 | 97.05 | 103.7 | 86.67 |
错误率% | 0 | 0 | 0 | 0 | 0 | 0 | 0(出现少量错误) | 0 | 1.2 | 7.3 | 10(压垮) | 17 |
结论:
- 同局域网压测,延迟增加,不能使用低并发去压测,因为大部分耗时都将耗费在网络延迟上,无法真正压出服务器的处理能力
- 处理能力下降,QPS最大值在800附近波动
- 持续增加连接数,当到达1线程/200连接时,开始少量出现错误;当连接数达到2000时,错误率上升至1.2%;当连接数持续增加至15000时,错误率上升至10%,系统被压垮 <==>相较于本机测试,相同连接数时,错误率相对更高。
- 错误类型以connect为主,详细分析:
- 通过在压测前后记录全连接/半连接队列满导致的丢包数量,发现大部分是因为队列满导致被丢弃,可通过修改队列长度获得性能提升
图1 - 本机并发线程压测时CPU消耗情况
图2 - 局域网单线程压测时CPU消耗情况
图3 - 广域网单线程压测时CPU消耗情况