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。

複製代碼

本文首發在掘金轉載請註明原做者,若是你以爲這篇文章對你有幫助或啓發,也能夠來請我喝咖啡。 利益相關:本篇文章全部涉及到的軟件均爲筆者平常所用工具,無任何廣告費用。

相關文章
相關標籤/搜索