HTTP压力测试教程
2023-02-05 00:00:00

这篇文章主要介绍HTTP压力测试的工具和一些特殊技巧,不会详细写使用方法,而是重点关注wrk这个压测工具,用它来测试多个性能指标。至于服务器端的调优可以参考前面几篇高并发配置文章。

压测工具介绍

  1. Apache JMeter:Apache JMeter 是一个开源的 Java 压力测试工具,可以通过图形化界面创建测试计划,并模拟用户请求、并发量等场景进行测试。
  2. ab:ab(Apache Bench)是一个简单的命令行式压力测试工具,可以模拟多个并发用户对目标 URL 进行请求,并提供基本的统计信息和报告功能。
  3. vegeta: Vegeta是一个通用的HTTP负载测试工具,它可以用恒定请求速率进行测试。它既可以用作命令行实用程序,也可以用作库。
  4. wrk: wrk 是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 epoll,kqueue 等,通过多线程和事件模式,对目标机器产生大量的负载。

还有很多压测工具,但是我只想详细说一下wrk和vegeta。主要推荐使用wrk来测试

注: 此文章这些工具都是使用Centos7安装部署的

vegeta

github地址: https://github.com/tsenart/vegeta

安装

vegeta安装非常简单,因为是go语言写的,可以直接下载官方的预编译版本后开箱即用。简单安装使用可以参考这篇文章https://www.cnblogs.com/zhangb8042/p/10237161.html。 此处不详细说

优势 & 缺点

优势如下:

  • vegeta性能很好。单个客户端就能提供很大吞吐量。
  • 支持多台客户端同时压测。因为单台客户端1个IP就会受到连接数端口限制,最多65535个端口。如果想测试最大并发连接数就需要多个客户端来压测。在github中提到过用pdsh可以实现,具体使用方法可以谷歌/百度一下。
  • 使用简单。命令行重要的参数不多,很容易掌握,支持多种请求方式。
  • 支持固定速率压测。

缺点我个人觉得有2个:

  • 压测文件可能会很大。如果压测吞吐量很大,而且压测时间很长,vegeta就会生成很大的压测文件,在生成报告时会占用很大时间。特别是多台压测时,几万QPS压测10分钟可能就有几个G的文件大小。
  • 没办法固定客户端的连接数。就是不支持客户端建立固定数量的TCP连接,这样不好测试最大并发连接数。

wrk

wrk github: https://github.com/wg/wrk
我更推荐使用wrk2,这个在wrk的基础上做了一些增强,可以支持固定吞吐量发压
wrk2 github: https://github.com/giltene/wrk2
多客户端wrk github: https://github.com/anio/wrk-utils

第三个地址是利用多客户端压测使用的(集群),可以配置多个发压客户端,通过一条命令直接启动,测试完结果会显示在控制端。

简单介绍

wrk2的使用可以参考github地址,也可以搜索一些使用文章参考。后续的都是使用wrk2进行测试的
举个例子:

wrk -t2 -c100 -d30s -R2000 http://127.0.0.1:8080/index.html

这条命令意思是使用2个线程(-t2),打开100个TCP连接(-c100),运行30s(-d30s),压测速度为2000/s (-R2000),请求接口为http://127.0.0.1:8080/index.html

在wrk-utils工具中,会有个stats.lua文件,如果会lua语言的话可以在里面修改一些请求代码,比如更改请求方式、请求类型、请求体、请求头等等,wrk可以支持lua语言。

wkr2+wrk-utils 安装+使用

当使用wrk-utils时,他自带的wrk不是wrk2,所以需要自己下载编译wrk2为可执行文件。
部署wrk2可以参考https://www.bilibili.com/read/cv9547855/
这篇文章是部署wrk的,但我们要使用wrk2,所以要替换下载wrk2的github文件。

然后部署wrk-utils很简单,只需要git clone到指定目录就可以,然后将生成的wrk2的可执行文件替换掉原来的wrk文件。多台服务器还需要安装sshpass,要配置免密登录。具体安装部署可以参考https://github.com/anio/wrk-utils
比较重要的步骤如下:

  1. 先确定好发压客户端,并且配置免密登录

  2. 在wrk-utils目录下新建一个servers.txt文件,写入客户端ip,一个ip一行。或者按教程填写此文件

  3. 执行命令如下命令启动,注意不要有/之类,直接复制即可

    . activate.sh

  4. 执行如下命令初始化

    init-servers

  5. available-node-count 命令可以显示可用的客户端节点数量,kill-all 命令可以停止所有的客户端进程

  6. 执行压测命令,等待执行完成就会显示测试结果

wrk-utils的命令一般如下所示:

exec-wrk 10 -t10 -c300 -d600s -R2000 -T60s –latency -s stats.lua ‘https://example.com/path/?id=1'

这些参数都是每台客户端独立执行的

  • 10 表示下一台机器执行wrk命令的延迟,也就是下一台机器延迟10s执行。因为如果瞬间几十台客户端发压,这个TCP新建连接速度会很大,如果服务器没做配置就会有大量失败。如果是测试吞吐量就应该避免瞬间流量过大,而是要慢慢升高压力。
  • -t10 表示客户端10个线程,这个是每台客户端都是10个线程,不是总共的
  • -c300 表示客户端建立300个TCP连接,这个也是每台客户端单独的
  • -d600s 表示压测600s,也就是10分钟
  • -R2000 表示压测速度为每秒2000次请求,wrk2提供
  • -T60s 表示超时时间60s
  • –latency 表示展现详细的测试结果,wrk2提供
  • -s stats.lua 加载lua脚本文件
  • https://example.com/path/?id=1' 请求的http接口

分析压测结果

测试完成可以看到结果输出,但是不会汇总,他是直接输出每一台客户端的结果,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Running 10s test @ http://127.0.0.1:8080
10 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 4.75ms 4.07ms 26.19ms 83.06%
Req/Sec -nan -nan 0.00 0.00%
Latency Distribution (HdrHistogram - Recorded Latency)
50.000% 2.86ms
75.000% 7.21ms
90.000% 10.47ms
99.000% 16.48ms
99.900% 20.96ms
99.990% 26.21ms
99.999% 26.21ms
100.000% 26.21ms

其中可以关注平均延迟,50%、90%、99%的请求延迟
之后会显示更精细的延迟数据,此处不再展示。最后会显示吞吐量等数据,如下所示

1
2
3
4
 1810 requests in 10.00s, 9.40MB read
Requests/sec: 180.95
Transfer/sec: 0.94MB
192.168.10.1 Done!

这就表示总共有1810个请求,压测10s,请求180.95次每秒,吞吐量 0.94MB每秒
此处的吞吐量是服务器实际的吞吐量,比如你压测1000次每秒,可能服务器只能做到200次每秒。

如果有异常,还可能会显示TCP socket的异常,如下所示

1
Socket errors: connect 1016, read 1968, write 33, timeout 1160

如果是测试http,对于这些输出可以不用太关注,但是如果输出包含如下内容,则表示出现了异常响应,就需要注意判断请求异常

1
Non-2xx or 3xx Responses: 20345

这个就表示出现了非200 和3xx 响应的请求数量。都知道200是表示请求成功,3开头的一般是重定向。所以这种就表示出现了异常,可以查看日志,判断响应码,然后再解决问题。查看日志可以到具体的客户端wrk-utils目录下查看wrk-done.log 文件,此文件会显示具体的返回响应码。

性能指标

  1. 吞吐量:吞吐量意味这台设备在每一秒以内所能够处理的最大流量或者说每一秒内能处理的数据包个数,或者说QPS、TPS之类。如果用带宽计量,单位是Mbps(Megabits per second)或者Gbps(Gigabits per second)
    吞吐量测试是最简单的,连接数不用太大,每台几百个就可以,慢慢提高压测速率,注意延迟,直到测试出极限,压测时间也要慢慢提高。
  2. 时延: 时延是系统处理请求所需要的时间。在一个网络中,如果我们访问某一台服务器,一般经过大量的路由交换设备,在路上就要耗费很多时间,所以服务处理请求的时间也很重要。我们压测一般都是内网压测,所以延迟基本就是服务器处理时间,所以这个数值越低越好。
    延迟不用单独测试,压测结果会包含延迟,重点关注平均延迟、50%请求的延迟、90%、99%、100%的延迟,可以看出整体状态。
  3. 新建连接速率: 新建连接速率指的是在每一秒以内服务器所能够处理的HTTP新建连连接请求的数量。用户每打开一个网页,访问一个服务器,在服务器看来会是1个甚至多个新建连接。而新建连接速率越高,就可以同时给更多的用户提供网络访问。比如设备的新建连接速率是1万,每人只会新建一个TCP连接,那么如果有1万人同时上网,那么所有的请求都可以在一秒以内完成,如果有1万1千人上网的话,那么前1万人可以在第一秒内完成,后1千个请求需要在下一秒才能完成。所以,新建连接速率高的服务器可以提供给更多人同时上网,提升用户的网络体验。
    新建连接速率要用特殊方法测试,因为普通测试对于HTTP1.1来说,建立了TCP连接之后就不会断开了,后续的请求都是用的同一个TCP连接,所以这样没办法测出新建连接速率。所以我们测试的时候要改请求头,将Connection 设置为close,这样客户端每次请求都会新建TCP连接。在wrk-utils中测试可以编辑stats.lua文件,增加如下代码即可

    wrk.headers[“Connection”] = “close”

服务器端可以用特定监控工具,如果是centos7也可以用以下命令查看:

sar -n TCP,ETCP 1

每秒都会输出TCP相关数据,其中passive_opens时每秒钟创建的被动套接字数量,也就相当于服务器的新建连接数了。因为每一次HTTP请求新建一个TCP连接,所以可以直接使用这个值

  1. 并发连接数:并发连接数就是指服务最大能够同时处理的连接会话个数。也就时能够维护的连接数的数量,现在普通的网站访问,一个用户一个浏览器一般会打开多个TCP连接,所以服务器这个指标越大,在一段时间内所能够允许同时上网的用户数越多。
    这个指标测试和新建连接速率差不多,但不同点是TCP连接不断开,而是一直维持不关闭。所以新增的请求头close要去掉,保持默认,wrk通过-T设置超时时间,要加大这个值,而且服务器也要调整超时时间,避免断开TCP连接。
    对于centos7可以使用ss -s查看当前TCP连接情况,也可以通过监控工具查看。执行ss -s命令输出如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Total: 2346 (kernel 2506)
    TCP: 944 (estab 575, closed 298, orphaned 0, synrecv 0, timewait 122/0), ports 0
    Transport Total IP IPv6
    * 2506 - -
    RAW 0 0 0
    UDP 9 7 2
    TCP 646 495 151
    INET 655 502 153
    FRAG 0 0 0
    其中TCP 中 estab 575就是当前的TCP已连接数量

注意要点

  1. 压测服务器一般要进行系统调优,centos默认的参数是没办法支持高并发的,这部分可以参考我之前的文章进行调整。
  2. 测试过程要时刻关注系统资源和负载,查看CPU、内存、磁盘和网络的使用情况,根据资源消耗调整压测参数。比如代理服务器可能会出现CPU过高,其他资源占用很少。有的服务器也可能出现软中断CPU过高,导致吞吐量上不去。有的可能会收到网线及网口限制。
  3. 压测要测出极限,也要测试正常使用状态的性能,避免突发流量导致服务异常。
  4. 一个压测工具可能会由于一些原因数值不准确,也可以使用其他工具进行压测,对比数据
  5. 压测要了解基本的TCP知识,比如握手挥手和TCP状态流转,要明白当前TCP各种状态出现的原因,比如大量TIME_WAIT一般是代理服务器出现,这个就可能导致压测性能上不去。
  6. 压测也要了解基本的HTTP知识,比如请求方式,请求类型,特定的请求头,这种都可能会对测试造成影响。
  7. 后端服务如果有必要可进行优化,比如通过监控进程线程的工具,或者火焰图工具,找到性能异常消耗的地方,进行性能调优