HTTP 基准测试工具
wrk
wrk 使用的是 HTTP/1.1
安装
需要从 GitHub 上克隆代码自己编译,编译前需要安装 git, gcc。
git clone https://github.com/wg/wrk.git
cd wrk
#使用多线程(机器的处理器核数)加速编译,
make -j $(nproc)
cp wrk /usr/local/bin/
测试
10 个线程,保持打开 100 个并发连接,持续 10 秒。
wrk -t10 -c100 -d10 http://www.baidu.com/
Running 10s test @ http://www.baidu.com/
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   138.46ms  219.05ms   1.89s    92.11%
    Req/Sec   128.07     79.83   700.00     94.40%
  12776 requests in 10.02s, 128.22MB read
  Socket errors: connect 0, read 57, write 0, timeout 3
Requests/sec:   1275.30
Transfer/sec:     12.80MB
打印详细的延时分布信息
wrk -c10 -t4 --latency http://www.baidu.com/
Running 10s test @ http://www.baidu.com/
  4 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    19.43ms    4.15ms 140.84ms   98.11%
    Req/Sec   103.13     10.00   121.00     75.75%
  Latency Distribution
     50%   18.64ms
     75%   19.05ms
     90%   21.04ms
     99%   27.75ms
  4110 requests in 10.01s, 41.14MB read
  Socket errors: connect 0, read 12, write 0, timeout 0
Requests/sec:    410.59
Transfer/sec:      4.11MB
不同的 HTTP 请求
发起 GET 请求(带查询参数)
wrk -c10 -t10 "http://127.0.0.1:8000/users?name=wjj&age=30"
URL 需要双引号,不然 &age=30 不会发送。
使用 POST 方式发送 键值 数据
Lua 脚本:post_x.lua
wrk.method = "POST"
wrk.body   = "name=wjj&age=40"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
测试
wrk -c1 -t1 -d1 -s post_x.lua  "http://127.0.0.1:8000/users"
使用 POST 方式发送 JSON 数据
Lua 脚本:post_json.lua
wrk.method = "POST"
wrk.body   = "{\"name\": \"wjj\", \"age\": 40}"
wrk.headers["Content-Type"] = "application/json"
测试
wrk -c1 -t1 -d1 -s post_json.lua  "http://127.0.0.1:8000/users_by_json"
使用 POST 方式发送文件
组织数据
通过 nc 捕获到的 form-data 发送文件的数据格式:
--------------------------f512f8a3c3a9b436\r\n
Content-Disposition: form-data; name="file"; filename="test.jpg"\r\n
Content-type: image/jpeg\r\n
\r\n
file content binary
\r\n
--------------------------f512f8a3c3a9b436--\r\n
可以编写个程序按上面的格式生成二进制的文件数据
我这里生成的数据:postdata
--1234567890^M
Content-Disposition: form-data; name="file"; filename="test.jpg"^M
Content-type: image/jpeg^M
^M
iVBORw0KGgoAAAANSUhEUgAACl4AAAesCAIAAABa4uohAAAACXBIWXMAAAsTAAALEwEAmpwYAAAgAElEQVR4nOzdfXyTZZ73/V/ShIZSSgqVxtpiaBE6SzuUgrNIFYGWBcW9R……..^M
--1234567890--^M
Lua 脚本:post_file.lua
wrk.method = "POST"
local f = io.open("postdata", "rb")
wrk.body   = f:read("*all")
wrk.headers["Content-Type"] = "multipart/form-data; boundary=1234567890"
测试
wrk -c1 -t1 -d1 -s post_file.lua  "http://127.0.0.1:8000/uploadfile"
ab
ab 使用的是 HTTP/1.0,不支持 HTTP/1.1
安装
- CentOS
    
yum install httpd-tools -y - Ubuntu
    
apt install apache2-utils -y 
测试
发起 200 个请求,并发 20 个请求。
ab -n200 -c20 http://www.baidu.com/
ab -p user.json -T "application/json" http://127.0.0.1:8000/users
发起 100 个并发讲求,持续 10 秒。
ab -c100 -t10 http://www.baidu.com/
Server Software:        BWS/1.1
Server Hostname:        www.baidu.com
Server Port:            80
Document Path:          /
Document Length:        347543 bytes
Concurrency Level:      100
Time taken for tests:   10.037 seconds
Complete requests:      333
Failed requests:        323
   (Connect: 0, Receive: 0, Length: 323, Exceptions: 0)
Total transferred:      134429279 bytes
HTML transferred:       133909888 bytes
Requests per second:    33.18 [#/sec] (mean)
Time per request:       3014.048 [ms] (mean)
Time per request:       30.140 [ms] (mean, across all concurrent requests)
Transfer rate:          13079.75 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       17   40 149.2     17    1074
Processing:    72 2161 1123.1   2068    6757
Waiting:       18   41  72.2     19     622
Total:         90 2201 1140.1   2106    6775
Percentage of the requests served within a certain time (ms)
  50%   2101
  66%   2538
  75%   2798
  80%   3059
  90%   3639
  95%   4103
  98%   5182
  99%   5521
 100%   6775 (longest request)
不同的 HTTP 请求
发起 GET 请求
ab http://www.baidu.com/
带参数的请求
ab "http://127.0.0.1:8000/users?name=wjj&age=30"
使用 POST 方式发送 键值 数据
文件:postdata.txt
name=wjj&age=40
发起一次请求
ab -v4 -p postdata.txt -T "application/x-www-form-urlencoded" http://127.0.0.1:8000/users 
使用 POST 方式发送 JSON 数据
文件:postdata.json
{
    "name": "wjj",
    "age": 40
}
发起一次请求
ab -v4 -p postdata.json -T "application/json" http://127.0.0.1:8000/users_by_json
使用 POST 方式发送文件
参考上面的组织数据
发起一次请求
ab -p postdata -T "multipart/form-data; boundary=1234567890" http://127.0.0.1:8000/uploadfile
这里的 boundary 值要比上面的数据格式少两个 ‘-‘ 字符
使用 POST 方式发送文件(base64)
macOS
echo -n '--1234567890\r\n' > post_data.txt
echo -n 'Content-Disposition: form-data; name="file"; filename="test.png"\r\n'>> post_data.txt
echo -n 'Content-type: image/png\r\n' >> post_data.txt
echo -n 'Content-Transfer-Encoding: base64\r\n' >> post_data.txt
echo -n '\r\n' >> post_data.txt
base64 test.png >> post_data.txt
echo -n '\r\n' >> post_data.txt
echo -n '--1234567890--\r\n' >> post_data.txt
Ubuntu
CentOS 运行下面命令,\r\n 变为4个字符而不是预期的2个字符。
echo -n '--1234567890\r\n' > post_data.txt
echo -n 'Content-Disposition: form-data; name="file"; filename="test.png"\r\n'>> post_data.txt
echo -n 'Content-type: image/png\r\n' >> post_data.txt
echo -n 'Content-Transfer-Encoding: base64\r\n' >> post_data.txt
echo -n '\r\n' >> post_data.txt
base64 -w0 test.png >> post_data.txt
echo -n '\r\n' >> post_data.txt
echo -n '--1234567890--\r\n' >> post_data.txt
ab -p post_data.txt -T "multipart/form-data; boundary=1234567890" http://127.0.0.1:8000/uploadfile
本来期望的是这个 base64 数据到了服务器端可以自动转成二进制的图像数据,没有成功,需要自己转。
基准测试工具
- wrk - a HTTP benchmarking tool
 - wrk2
 - ab - Apache HTTP server benchmarking tool
 - WAF-Bench (wb): a benchmarking tool for Web Application Firewall (WAF)
 - JMeter
 - autocannon - fast HTTP/1.1 benchmarking tool written in Node.js
 
参考资料
- ab(1) - Linux man page
 - How To Benchmark HTTP Latency with wrk on Ubuntu 14.04
 - WRK the HTTP benchmarking tool - Advanced Example
 - POST request with wrk?
 - Web 高并发压测工具之 WRK, AB
 - 性能测试工具 wrk 使用教程
 - Wrk
 - 腾讯云开发手册 HTTP Headers Content-Disposition
 - How to send binary file as body? #382
 - MIME Headers Content-Type: application
 - Python binary file write directly from string
 - save string to a binary file in python
 - Post请求Content-Type方式区分(PostMan示例form-data,x-www-form-urlencoded,raw,binary)
 - JMeter压力测试/并发测试/性能测试入门教程
 - Apache bench test POST with image file contents
 - Use Apache Bench (AB) to Test a Website’s Server
 - 四种常见的 POST 提交数据方式(application/x-www-form-urlencoded,multipart/form-data,application/json,text/xml)
 - Example of using Apache Bench (ab) to POST JSON to an API
 - post使用form-data和x-www-form-urlencoded的本质区别
 - Web性能测试篇:AB 压力测试
 - Multipart/form-data POST文件上传详解
 - Difference between CR LF, LF and CR line break types?
 - POSTing multipart/form-data with Apache Bench (ab)
 - Benchmarking file uploads
 - POST Data to Load Test with ApacheBench
 - HTTP POST Request Method