面试官:说说你以前负责的系统,QPS 能达到多少?

图片

被面试官常常问到以前开发的系统接口 QPS 能达到多少,又给不出一个数值,支支吾吾,致使总体面试效果下降?html

缘由基本是一些公司中,作完功能测试就完了,压根不会有性能测试这一步,或者说并发量较少,没有必要进行性能测试,亦或者,交给测试人员后,只要总体问题不大,测试报告通常也是不会再给后端人员看的,这就致使咱们在面试的时候,场面一度尴尬 !!!git

其实,不仅仅是针对面试,做为一名后端开发者,咱们在完成一个接口开发后,在交给测试工程师以前,常常也会想知道,本身写的这个接口的性能如何呢?吞吐量能达到多少?QPS(Query per second 每秒处理完的请求数) 能达到多少呢?github

这个时候,咱们就须要借助一些经常使用的性能测试工具,如 Apache ab, Apache JMeter (互联网公司用的较多),LoadRunner 等。面试

咱们今天主要说一说轻量级性能测试工具 wrkredis

目录

1、什么是 wrk 2、 wrk 的优点&劣势后端

  • 2.1 优点centos

  • 2.2 劣势bash

3、wrk 安装服务器

  • 3.1 Linux 安装多线程

  • 3.2 MacOS 安装

  • 3.3 Window 10 安装

  • 3.4 验证一下,是否安装成功

4、如何使用

  • 4.1 简单使用

  • 4.2 wrk 子命令参数说明

  • 4.3 测试报告

  • 4.4 使用 Lua 脚本进行复杂测试

5、总结 6、参考文档

1、什么是 wrk

摘自官方 GitHub 上的英文介绍:

图片

翻译一下:

wrk 是一款针对 Http 协议的基准测试工具,它可以在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 epoll,kqueue 等,经过多线程和事件模式,对目标机器产生大量的负载。

PS: 其实,wrk 是复用了 redis 的 ae 异步事件驱动框架,准确来讲 ae 事件驱动框架并非 redis 发明的, 它来至于 Tcl 的解释器 jim, 这个小巧高效的框架, 由于被 redis 采用而被你们所熟知。

2、 wrk 的优点&劣势

2.1 优点

在说 wrk 的优点以前,瞅一下 wrk 的 GitHub Star 数,也能侧面反映下它的可靠性:

图片

Wow ! 截止笔者截图为止, Star 数已经达到了 19742 !!!

再来讲说 wrk 的优点:

  • 轻量级性能测试工具;

  • 安装简单(相对 Apache ab 来讲);

  • 学习曲线基本为零,几分钟就能学会咋用了;

  • 基于系统自带的高性能 I/O 机制,如 epoll, kqueue, 利用异步的事件驱动框架,经过不多的线程就能够压出很大的并发量;

2.2 劣势

wrk 目前仅支持单机压测,后续也不太可能支持多机器对目标机压测,由于它自己的定位,并非用来取代 JMeter, LoadRunner 等专业的测试工具,wrk 提供的功能,对咱们后端开发人员来讲,应付平常接口性能验证仍是比较友好的。

3、wrk 安装

wrk 只能被安装在类 Unix 系统上,因此咱们须要一个 Linux 或者 MacOS 环境。Windows 10 安装须要开启自带的 Ubuntu 子系统。

3.1 Linux 安装

3.1.1 Ubuntu/Debian

依次执行以下命令:

sudo apt-get install build-essential libssl-dev git -y
git clone https://github.com/wg/wrk.git wrk
cd wrk
make
# 将可执行文件移动到 /usr/local/bin 位置
sudo cp wrk /usr/local/bin

3.2.2 CentOS / RedHat / Fedora

依次执行以下命令:

sudo yum groupinstall 'Development Tools'
sudo yum install -y openssl-devel git 
git clone https://github.com/wg/wrk.git wrk
cd wrk
make
# 将可执行文件移动到 /usr/local/bin 位置
sudo cp wrk /usr/local/bin

3.2 MacOS 安装

Mac 系统也能够经过先编译的方式来安装,可是更推荐使用 brew的方式来安装, 步骤以下:

  1. 安装 Homebrew,安装方式参考官网 https://brew.sh (也就一行命令的事);

  2. 安装 wrk: brew install wrk;

3.3 Window 10 安装

Windown 10 须要在 Windows功能 里勾选 适用于LinuxWindows子系统, 而后经过 bash 命令切换到 Ubuntu 子系统。接下来,参考3.1.1 Ubuntu 的操做系通中,安装 wrk 的步骤。

因为笔者使用的是 MacOS, Windows 上的安装步骤,并无实际操做过,具体安装步骤,您能够参考官方 Windows 10 的安装教程:https://github.com/wg/wrk/wiki/Installing-wrk-on-Windows-10 ,或者用您喜欢的搜索引擎来搜索 Windows 10 如何启用 Ubuntu 子系统后,再安装 wrk,亦或者经过安装 Linux 虚拟机的方式来使用 wrk。

3.4 验证一下,是否安装成功

命令行中输入命令:

wrk -v

图片

输出如上信息,说明安装成功了!

4、如何使用

安装成功了,要如何使用呢?

4.1 简单使用

wrk -t12 -c400 -d30s http://www.baidu.com

这条命令表示,利用 wrk 对 www.baidu.com 发起压力测试,线程数为 12,模拟 400 个并发请求,持续 30 秒。

4.2 wrk 子命令参数说明

除了上面简单示例中使用到的子命令参数, wrk 还有其余更丰富的功能,命令行中输入 wrk--help, 能够看到支持如下子命令:


  1. [root@VM_0_5_centos ~]# wrk --help

  2. Usage: wrk <options> <url>                            

  3.  Options:                                            

  4.    -c, --connections <N>  Connections to keep open  

  5.    -d, --duration    <T>  Duration of test          

  6.    -t, --threads     <N>  Number of threads to use  


  7.    -s, --script      <S>  Load Lua script file      

  8.    -H, --header      <H>  Add header to request      

  9.        --latency          Print latency statistics  

  10.        --timeout     <T>  Socket/request timeout    

  11.    -v, --version          Print version details      


  12.  Numeric arguments may include a SI unit (1k, 1M, 1G)

  13.  Time arguments may include a time unit (2s, 2m, 2h)

翻译一下:


  1. 使用方法: wrk <选项> <被测HTTP服务的URL>                            

  2.  Options:                                            

  3.    -c, --connections <N>  跟服务器创建并保持的TCP链接数量  

  4.    -d, --duration    <T>  压测时间          

  5.    -t, --threads     <N>  使用多少个线程进行压测  


  6.    -s, --script      <S>  指定Lua脚本路径      

  7.    -H, --header      <H>  为每个HTTP请求添加HTTP      

  8.        --latency          在压测结束后,打印延迟统计信息  

  9.        --timeout     <T>  超时时间    

  10.    -v, --version          打印正在使用的wrk的详细版本信息


  11.  <N>表明数字参数,支持国际单位 (1k, 1M, 1G)

  12.  <T>表明时间参数,支持时间单位 (2s, 2m, 2h)

PS: 关于线程数,并非设置的越大,压测效果越好,线程设置过大,反而会致使线程切换过于频繁,效果下降,通常来讲,推荐设置成压测机器 CPU 核心数的 2 倍到 4 倍就好了。

4.3 测试报告

执行压测命令:

wrk -t12 -c400 -d30s --latency http://www.baidu.com

执行上面的压测命令,30 秒压测事后,生成以下压测报告:

Running 30s test @ http://www.baidu.com 
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   386.32ms  380.75ms   2.00s    86.66%
    Req/Sec    17.06     13.91   252.00     87.89%
  Latency Distribution
     50%  218.31ms
     75%  520.60ms
     90%  955.08ms
     99%    1.93s 
  4922 requests in 30.06s, 73.86MB read
  Socket errors: connect 0, read 0, write 0, timeout 311
Requests/sec:    163.76
Transfer/sec:      2.46MB

咱们来具体说一说,报告中各项指标都表明什么意思:

Running 30s test @ http://www.baidu.com (压测时间30s)
  12 threads and 400 connections (共12个测试线程,400个链接)
              (平均值) (标准差)  (最大值)(正负一个标准差所占比例)
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    (延迟)
    Latency   386.32ms  380.75ms   2.00s    86.66%
    (每秒请求数)
    Req/Sec    17.06     13.91   252.00     87.89%
  Latency Distribution (延迟分布)
     50%  218.31ms
     75%  520.60ms
     90%  955.08ms
     99%    1.93s 
  4922 requests in 30.06s, 73.86MB read (30.06s内处理了4922个请求,耗费流量73.86MB)
  Socket errors: connect 0, read 0, write 0, timeout 311 (发生错误数)
Requests/sec:    163.76 (QPS 163.76,即平均每秒处理请求数为163.76)
Transfer/sec:      2.46MB (平均每秒流量2.46MB)

能够看到,压测报告仍是很是直观的!

标准差啥意思?标准差若是太大说明样本自己离散程度比较高,有可能系统性能波动较大。

4.4 使用 Lua 脚本进行复杂测试

您可能有疑问了,你这种进行 GET 请求还凑合,我想进行 POST 请求咋办?并且我想每次的请求参数都不同,用来模拟用户使用的实际场景,又要怎么弄呢?

对于这种需求,咱们能够经过编写 Lua 脚本的方式,在运行压测命令时,经过参数 --script 来指定 Lua 脚本,来知足个性化需求。

4.4.1 wrk 对 Lua 脚本的支持

wrk 支持在三个阶段对压测进行个性化,分别是启动阶段、运行阶段和结束阶段。每一个测试线程,都拥有独立的Lua 运行环境。

启动阶段:

function setup(thread)

在脚本文件中实现 setup 方法,wrk 就会在测试线程已经初始化,但尚未启动的时候调用该方法。wrk会为每个测试线程调用一次 setup 方法,并传入表明测试线程的对象 thread 做为参数。setup 方法中可操做该 thread 对象,获取信息、存储信息、甚相当闭该线程。

thread.addr             - get or set the thread's server address
thread:get(name)        - get the value of a global in the thread's env
thread:set(name, value) - set the value of a global in the thread's env
thread:stop()           - stop the thread

运行阶段:

function init(args)
function delay()
function request()
function response(status, headers, body)
  • init(args): 由测试线程调用,只会在进入运行阶段时,调用一次。支持从启动 wrk 的命令中,获取命令行参数;

  • delay(): 在每次发送请求以前调用,若是须要定制延迟时间,能够在这个方法中设置;

  • request(): 用来生成请求, 每一次请求都会调用该方法,因此注意不要在该方法中作耗时的操做;

  • response(status,headers,body): 在每次收到一个响应时被调用,为提高性能,若是没有定义该方法,那么wrk不会解析 headers 和 body

结束阶段:

function done(summary, latency, requests)

done() 方法在整个测试过程当中只会被调用一次,咱们能够从给定的参数中,获取压测结果,生成定制化的测试报告。

自定义 Lua 脚本中可访问的变量以及方法:

变量:wrk

wrk = {
    scheme  = "http",
    host    = "localhost",
    port    = 8080,
    method  = "GET",
    path    = "/",
    headers = {},
    body    = nil,
    thread  = <userdata>,
  }

以上定义了一个 table 类型的全局变量,修改该 wrk 变量,会影响全部请求。

方法:

  1. wrk.fomat

  2. wrk.lookup

  3. wrk.connect

上面三个方法解释以下:


  1. function wrk.format(method, path, headers, body)


  2.    wrk.format returns a HTTP request string containing the passed parameters

  3.    merged with values from the wrk table.

  4.    # 根据参数和全局变量 wrk,生成一个 HTTP rquest 字符串。


  5. function wrk.lookup(host, service)


  6.    wrk.lookup returns a table containing all known addresses for the host

  7.    and service pair. This corresponds to the POSIX getaddrinfo() function.

  8.    # 给定 host 和 service(port/well known service name),返回全部可用的服务器地址信息。


  9. function wrk.connect(addr)


  10.    wrk.connect returns true if the address can be connected to, otherwise

  11.    it returns false. The address must be one returned from wrk.lookup().

  12.    # 测试给定的服务器地址信息是否能够成功建立链接

4.4.1 经过 Lua 脚本压测示例

调用 POST 接口:

request = function()
   uid = math.random(1, 10000000)
   path = "/test?uid=" .. uid
   return wrk.format(nil, path)
end

注意: wrk 是个全局变量,这里对其作了修改,使得全部请求都使用 POST 的方式,并指定了 body 和 Content-Type头。

自定义每次请求的参数:

request = function()
   uid = math.random(1, 10000000)
   path = "/test?uid=" .. uid
   return wrk.format(nil, path)
end

在 request 方法中,随机生成 1~10000000 之间的 uid,并动态生成请求 URL.

每次请求前,延迟 10ms:

function delay()
   return 10
end

请求的接口须要先进行认证,获取 token 后,才能发起请求,咋办?


  1. token = nil

  2. path  = "/auth"


  3. request = function()

  4.   return wrk.format("GET", path)

  5. end


  6. response = function(status, headers, body)

  7.   if not token and status == 200 then

  8.      token = headers["X-Token"]

  9.      path  = "/test"

  10.      wrk.headers["X-Token"] = token

  11.   end

  12. end

上面的脚本表示,在 token 为空的状况下,先请求 /auth 接口来认证,获取 token, 拿到 token 之后,将 token 放置到请求头中,再请求真正须要压测的 /test 接口。

压测支持 HTTP pipeline 的服务:


  1. init = function(args)

  2.   local r = {}

  3.   r[1] = wrk.format(nil, "/?foo")

  4.   r[2] = wrk.format(nil, "/?bar")

  5.   r[3] = wrk.format(nil, "/?baz")


  6.   req = table.concat(r)

  7. end


  8. request = function()

  9.   return req

  10. end

经过在 init 方法中将三个 HTTP请求拼接在一块儿,实现每次发送三个请求,以使用 HTTP pipeline。

5、总结

本文中,咱们学习了轻量级性能测试工具 wrk, 如何安装,以及具体的使用方法,包括经过 Lua 脚原本个性化定制请求等。但愿读完本文,能对您有所帮助哦!

6、参考文档:

  • https://github.com/wg/wrk

  • https://zjumty.iteye.com/blog/2221040

  • http://www.cnblogs.com/xinzhao/p/6233009.html

图片

相关文章
相关标签/搜索