ab和wrk接口压测实践

| 导语 平常运营作活动会带来很大的请求量,为了评估当前系统是否能支撑住预估的请求量,那么就对访问量大的接口作压测,通常会进行多轮压测,主要是排查系统隐藏的bug和发现能够优化的点,而后根据压测结果评估当前系统负载,而后准备扩容等工做,使系统能稳定可靠的支撑运营活动。nginx

压测术语说明

1. 吞吐率

概念:服务器并发处理能力的量化描述,单位是reqs/s,指的是某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。 计算公式:总请求数 / 处理完成这些请求数所花费的时间,即 Request per second = Complete requests / Time taken for testsgit

2. 并发链接数

概念:某个时刻服务器所接受的请求数目github

3. 并发用户数

概念:要注意区分这个概念和并发链接数之间的区别,一个用户可能同时会产生多个会话,也即链接数。apache

4.用户平均请求等待时间

计算公式:处理完成全部请求数所花费的时间/ (总请求数 / 并发用户数),即 Time per request = Time taken for tests /( Complete requests / Concurrency Level)json

以上是咱们压测关心的一些指标,其中吞吐率是咱们最关心的指标。windows

1. 压测工具ab实践

ab用法介绍

这里介绍经常使用的参数和用法api

-n requests 总请求数
-c concurrency 一次产生的请求数,能够理解为并发数
-t timelimit 测试所进行的最大秒数, 能够当作请求的超时时间
-p postfile 包含了须要POST的数据的文件
-T content-type POST数据所使用的Content-type头信息
复制代码

get请求:ab -n 1000 -c 10 -t 10 "testurl.com/get_user?ui…"bash

post请求:ab -n 1000 -c 10 -t 10 -p post.json -T "application/x-www-form-urlencoded" "testurl.com/add_user" 其中post.json是你的那个接口须要的json参数服务器

{"name":"bob","age":12,"sex":1}
复制代码

编写脚本批量压测接口(多个同时同时压测)

在实际压测中,咱们每每要压测不少接口,而不少接口都有同时请求的状况,因此咱们不能单独一个一个测接口获得TPS,因此须要本身编写脚本,去完成同时压测的要求。如下是写的一个简单的批量压测脚本test.sh:多线程

#!/bin/sh 
RESULT_DIR="/data/home/yawenxu/TestResult/"
jsonFileArr="ff0e_00.json ff0e_02.json ff0e_05.json ff0e_06.json ff0e_07.json ff0e_08.json ff0e_10.json ff0e_11.json" # 每一个接口post须要的json参数的文件
concurrency=${1-1} #并发数
count=${2-1}  #总请求数
input_file_name=$3
exec_single_ab(){
        if [ -f $1 ];then
                /usr/bin/ab -n $2 -c $3 -p $1 -T "application/x-www-form-urlencoded" "http://$4" >$RESULT_DIR$1$2"_nginx.txt" 2>&1 &
        else
                echo $1" is not exists"
        fi

}
exec_loop_ab(){
        for item_name in $jsonFileArr
        do
                exec_single_ab $item_name $concurrency $count "http://api.com/xxx" &
        done
}

if [ -f $input_file_name ];then
        exec_single_ab $input_file_name $concurrency $count &
else
        exec_loop_ab &
fi

复制代码

这个脚本保证了多个接口同时压测,同时将每一个接口的压测报告保存到文件里,便于分析。执行命令sh test.sh 10000 10000 一次性生成压测报告文件以下:

ff0e_00.json10000_nginx.txt  ff0e_05.json10000_nginx.txt  ff0e_07.json10000_nginx.txt  ff0e_10.json10000_nginx.txt
ff0e_02.json10000_nginx.txt  ff0e_06.json10000_nginx.txt  ff0e_08.json10000_nginx.txt  ff0e_11.json10000_nginx.txt
复制代码

某个文件的压测报告以下图

This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.voovlive.com (be patienComCompleted 100 requesComCompleted 200 requesComCompleted 300 requesComCompleted 400 requesCompleted 500 requests
Finished 500 requests


Server Software:        
Server Hostname:        10.228.15.46
Server Port:            3002

Document Path:          /test/get
Document Length:        248 bytes

Concurrency Level:      500
Time taken for tests:   2.523 seconds
Complete requests:      500
Failed requests:        0
Write errors:           0
Total transferred:      161500 bytes
Total POSTed:           359640
HTML transferred:       124000 bytes
Requests per second:    198.19 [#/sec] (mean)
Time per request:       2522.808 [ms] (mean)
Time per request:       5.046 [ms] (mean, across all concurrent requests)
Transfer rate:          62.52 [Kbytes/sec] received
                        139.21 kb/s sent
                        201.73 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   13   4.1     14      17
Processing:   416  948 516.2    828    2485
Waiting:      415  947 516.4    827    2485
Total:        432  961 513.2    841    2497

Percentage of the requests served within a certain time (ms)
  50%    841
  66%    913
  75%    990
  80%   1213
  90%   2039
  95%   2064
  98%   2476
  99%   2484
 100%   2497 (longest request)
uest)
复制代码

咱们比较关心的几个点 1.Concurrency Level: 500 // 并发数 2.Time taken for tests: 2.523 seconds // 总花费时间 3.Complete requests: 500 // 完成请求数 4.Failed requests: 0 // 失败请求数 5.Requests per second: 198.19 [#/sec] (mean) // 吞吐率(TPS) 6.Time per request: 2522.808 [ms] (mean) // 一个请求花费的平均时间 7.Percentage of the requests served within a certain time (ms) // 请求的时间分布状况 压测主要是评估当前系统的负载,因此通常看看吞吐率(TPS)和成功率就够了,若是想评估接口性能,能够查看第6和第7项数据。每每须要改变压测参数(并发数和总请求数)多压测几回,才会获得准确的TPS。

问题总结

ab优势以下:

1. 简单易用
2. 支持post请求,接受json文件做为参数 (方便编写脚本批量测试)
3. 压测量不大的状况下够用(1024个并发如下)
复制代码

可是也有一些明显缺点

1. 没法持续时间压测,控制速度压测。ab没有这个功能。
2. 压测量起不来。主要是ab只能利用单个cpu,只能是单进程,而系统限制每一个进程打开的最大文件数为1024,因此最多1024个线程,若是是多核cpu,就浪费了这些资源。
3. 若是中途的请求被服务器拒绝了,测试报告不完整,没法得出已完成请求的压测状况。如下是中途被服务器拒绝的报告,很不友好:
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 100.125.176.120 (be patienCompleted 100 requests
Completed 200 requests
ComCompleted 300 requesComCompleted 400 requesComCompleted 500 requesapr_socket_recv: Connection timed out (110)
Total of 536 requests completed
ed

复制代码

2.压测工具wrk实践

发现ab的这些缺点,没法知足目前的压测要求以后,去查看了不少压测工具,最后发现了wrk这个一样易用,没有上面ab的缺点,使用学习成本稍高一点的压测工具。 wrk负载测试时能够运行在一个或者多核CPU,wrk结合了可伸缩的事件通知系统epoll和kqueue等多线程设计思想。

wrk用法介绍

1. 安装

压测是在测试环境的机器上进行的,因为测试环境机器访问不了外网因此安装一些工具较为麻烦。为何要到测试环境机器上进行呢?由于

1. 本机windows环境,安装一样比较麻烦
2. 压测现网服务有些是经过ip压测的,本机没法访问。
3. 测试环境机器性能比较高,并发请求量更大一些。
复制代码

安装步骤以下

  1. 下载安装包到本地源码地址
  2. 本地上传压缩包到测试环境机器
  3. 在测试环境解压,编译,若是编译报错,少了一些依赖库,按照一样的步骤安装。

2. 主要参数说明

-t --threads   开启的线程数,用于控制并发请求速度。最大值通常是cpu总核心数的2-4倍
-c --conections 保持的链接数(会话数)
-d --duration 压测持续时间(s)
-s --script 加载lua脚本(post请求写一些参数到脚本里)
-H --header 在请求头部添加一些参数
--latency 压测报告输出请求回包花费时间分布
--timeout 请求的最大超时时间(s),这个颇有用
复制代码

简单的例子 wrk -t4 -c1000 -d30s -T30s --latency www.baidu.com 上面这条命令的意思是用4个线程来模拟1000个并发链接,整个测试持续30秒,链接超时30秒,打印出请求的延迟统计信息。

编写脚本批量压测接口(多个接口同时压测)

1.编写lua脚本 由于接口须要json格式参数,因此首先编写lua脚本,在lua脚本里添加json参数, ff0e_05.lua以下

request = function()
    local headers = { }
    headers['Content-Type'] = "application/json"
    body = '{"uin":"123","lang":"en"}'
    return wrk.format('POST', nil, headers, body)
end
复制代码
  1. 编写压测脚本 一个简单的批量压测脚本test.sh:
#!/bin/sh 
RESULT_DIR="/data/home/yawenxu/wrkTestResult/"
luaFileArr="ff0e_00.lua ff0e_02.lua ff0e_05.lua ff0e_06.lua ff0e_07.lua ff0e_08.lua ff0e_10.lua ff0e_11.lua" # 每一个接口post须要的json参数的lua文件
concurrency=${1-1} #开启线程数,用于控制速度
count=${2-1}  #保持链接数
continueTime=${3-1}  # 持续时间
input_file_name=$4
exec_single_wrk(){
        if [ -f $1 ];then
                ./wrk -t $2 -c $3 -d $continueTime --script=$1 --latency --timeout 10 "http://$4" >$RESULT_DIR$1$3"_nginx.txt" 2>&1 &
        else
                echo $1" is not exists"
        fi
}

exec_loop_wrk(){
        for item_name in $luaFileArr
        do
                exec_single_wrk $item_name $concurrency $count "http://api.com/xxx" &
        done
}

if [ -f $input_file_name ];then
        exec_single_wrk $input_file_name $concurrency $count &
else
        exec_loop_wrk &
fi

复制代码

这个脚本保证了多个接口同时压测,同时将每一个接口的压测报告保存到文件里,便于分析。执行命令sh test.sh 12 5000 10 会一次性生成全部接口的压测报告文件,其中一份压测报告以下:

Running 10s test @ http://api.com/xxx
  12 threads and 5000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.27s   386.53ms   1.99s    59.87%
    Req/Sec    53.85     75.74   777.00     93.91%
  Latency Distribution
     50%    1.26s
     75%    1.61s
     90%    1.80s
     99%    1.97s
  3641 requests in 10.10s, 1.88MB read
  Socket errors: connect 0, read 0, write 0, timeout 2146
Requests/sec:    360.51
Transfer/sec:    190.82KB
复制代码

看上面的报告,能够看出保持链接数5000,持续压测10s,超时时间10s,这种状况接口超时状况特别严重,总请求数3641超时数目2146,可是查看 Latency Distribution又发现99%的请求都在1.97s内回包,这个时候就要考虑nginx接入层的转发能力是否是比较低致使的。因此咱们能够压测下咱们服务的具体ip,不经过nginx接入层。最后压测发现的确是nginx流量转发有评价瓶颈,那咱们能够采起扩容nginx的措施。

在作脚本压测的同时,须要实时查看现网服务的cpu使用率和系统负载状况,发现cpu使用率和负载明显飙升。命令:top -d 1,能够参考使用 Perf 和火焰图分析 CPU 性能

问题总结

  1. 压测不能作单独接口的压测,必须模拟实际状况,对实际有同时请求的不少接口同时压测,这样才能发现系统的问题
  2. 压测须要考虑多方面因素。
1. 压测所用机器的性能,每秒发出的请求数能不能达到预估值
2. 压测工具每秒发出的请求数能不能达到预估值,以及能不能持续压测。
3. 压测现网服务,须要考虑到依赖的其余服务,好比接入层(nginx)自身的处理能力,能够对接入层作压测。
4. 压测的时候须要实时查看现网服务的cpu使用率和系统负载状况,这个能够发现编码上的bug。

复制代码

本文首发在掘金转载请注明原做者,若是你以为这篇文章对你有帮助或启发,也能够来请我喝咖啡。 利益相关:本篇文章全部涉及到的软件均为笔者平常所用工具,无任何广告费用。

相关文章
相关标签/搜索