一、背景

通过压测发现系统瓶颈,评估系统 QPS、吞吐量上限

二、工具选择

ab、wrk、Jmeter

ab

[root@VM-190-129-centos ~]# ab --help
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
    -n requests     Number of requests to perform(总请求数)
    -c concurrency  Number of multiple requests to make at a time(并发请求数)
    -t timelimit    Seconds to max. to spend on benchmarking
                    This implies -n 50000
    -s timeout      Seconds to max. wait for each response
                    Default is 30 seconds
    -b windowsize   Size of TCP send/receive buffer, in bytes
    -B address      Address to bind to when making outgoing connections
    -p postfile     File containing data to POST. Remember also to set -T(POST 请求体文件,需配合 -T)
    -u putfile      File containing data to PUT. Remember also to set -T
    -T content-type Content-type header to use for POST/PUT data, eg.(设置 Content-Type 请求头)
                    'application/x-www-form-urlencoded'
                    Default is 'text/plain'
    -v verbosity    How much troubleshooting info to print
    -w              Print out results in HTML tables
    -i              Use HEAD instead of GET
    -x attributes   String to insert as table attributes
    -y attributes   String to insert as tr attributes
    -z attributes   String to insert as td or th attributes
    -C attribute    Add cookie, eg. 'Apache=1234'. (repeatable)(设置 cookie)
    -H attribute    Add Arbitrary header line, eg. 'Accept-Encoding: gzip'(设置请求头)
                    Inserted after all normal header lines. (repeatable)
    -A attribute    Add Basic WWW Authentication, the attributes
                    are a colon separated username and password.
    -P attribute    Add Basic Proxy Authentication, the attributes
                    are a colon separated username and password.
    -X proxy:port   Proxyserver and port number to use(指定使用的代理服务器和端口号,例如 "127.0.0.1:88")
    -V              Print version number and exit
    -k              Use HTTP KeepAlive feature(是否开启长连接)
    -d              Do not show percentiles served table.
    -S              Do not show confidence estimators and warnings.
    -q              Do not show progress when doing more than 150 requests
    -g filename     Output collected data to gnuplot format file.(输出结果信息到 gnuplot 格式文件)
    -e filename     Output CSV file with percentages served(输出结果信息到 CSV 格式文件)
    -r              Don't exit on socket receive errors.
    -h              Display usage information (this message)
    -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)
    -f protocol     Specify SSL/TLS protocol
                    (SSL3, TLS1, TLS1.1, TLS1.2 or ALL)

wrk

[root@cdntest-wrk-0 ~]# wrk --help
Usage: wrk <options> <url>                            
  Options:                                            
    -c, --connections <N>  Connections to keep open(并发数)
    -d, --duration    <T>  Duration of test(持续时间/秒)           
    -t, --threads     <N>  Number of threads to use(线程数)   
                                                      
    -s, --script      <S>  Load Lua script file(从 Lua 文件中读取请求信息)       
    -H, --header      <H>  Add header to request(设置请求头)      
        --latency          Print latency statistics   
        --timeout     <T>  Socket/request timeout     
    -v, --version          Print version details      
                                                      
  Numeric arguments may include a SI unit (1k, 1M, 1G)
  Time arguments may include a time unit (2s, 2m, 2h)

通过解读 ab 和 wrk 关键参数可知:
1.ab 不支持从文件或使用编码,动态修改 POST 或 url 信息;
2.通过 google 了解到 ab 不支持多线程。
以上两个特性 wrk 可以支持,而 Jmeter 需安装 GUI,没有 CLI 方便没有详细去了解,选择用 wrk 进行压测。

三、示例

命令

wrk -t1 -c1 -d1s -s post.lua --latency http://127.0.0.1:8080/index.php

使用 lua 脚本,实现 POST 请求动态参数组装

post.lua

--压测命令
--wrk -t1 -c1 -d1s -s post.lua --latency http://127.0.0.1:8080/index.php

--单条全局测试
--wrk.method = "POST"
--wrk.headers["Content-Type"] = "application/json"
--wrk.body = '{"Urls":"http://127.0.0.1","Action":"Test"}'
--os.exit()

--函数:删除字符串尾部逗号
function rtrim_comma(input)
    return (string.gsub(input, "[,]+$", ""))
end

--[[
--调试
url = 'http://127.0.0.1/'
urls = ''
r = math.random(10000000,99999999)
for i=1,10,1 do
    -- print(i)
    urls = urls .. '"' .. url .. r .. '/' .. i .. '",'
end
urls = rtrim_comma(urls)
print(urls)
body = '{"Urls":['.. urls ..'],"Action":"Test"}'
print(body)
--]]

--全局参数
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"

--每个请求参数
request = function()
    --动态拼接 POST 中的 Urls 参数
    url = 'http://127.0.0.1/'
    urls = ''
    r = math.random(10000000,99999999)
    for i=1,10,1 do
        -- print(i)
        urls = urls .. '"' .. url .. r .. '/' .. i .. '",'
    end
    urls = rtrim_comma(urls)

    body = '{"Urls":['.. urls ..'],"Action":"Test"}'
    --print(body)
  return wrk.format(nil, nil, nil, body)
end