面試官:說說你以前負責的系統,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

圖片

相關文章
相關標籤/搜索