1. 程式人生 > >伺服器API壓力測試 -ab工具

伺服器API壓力測試 -ab工具

最近對伺服器的某些api進行效能測試,我們關注的主要指標就是系統吞吐量。 第三節看看就好,很久前寫的。

1 系統吞吐量的簡單介紹

一個系統的吞度量(承壓能力)與request對CPU的消耗、外部介面、IO等等緊密關聯。
單個reqeust 對CPU消耗越高,外部系統介面、IO影響速度越慢,系統吞吐能力越低,反之越高。

系統吞吐量幾個重要引數:QPS(TPS)、併發數、響應時間

  • QPS(TPS):每秒鐘request/事務 數量
  • 併發數: 系統同時處理的request/事務數
  • 響應時間: 一般取平均響應時間
    QPS(TPS)= 併發數/平均響應時間

Tps:在實際測試中表現為:

一個系統吞吐量通常由QPS(TPS)、併發數兩個因素決定,每套系統這兩個值都有一個相對極限值,在應用場景訪問壓力下,只要某一項達 到系統最高值,系統的吞吐量就上不去了,如果壓力繼續增大,系統的吞吐量反而會下降,原因是系統超負荷工作,上下文切換、記憶體等等其它消耗導致系統性能下降。
實際表現為tps即先上升後下降,我們需要找到效能拐點。並得到限制瓶頸。

2 測試方法

2.1 客戶端測試工具

我們採用apacheBench 工具進行測試。

ubuntu安裝ab:

sudo apt-get install apache2-utils 

linux預設登入埠只能開啟1024個檔案,因為在linux一切皆檔案,所以ab併發數受到整個開啟檔案數的限制,需要使用ulimit -n 10000(開啟檔案數)進行修改後才能支援較大的併發。本人測試修改到15000。

2.1.1 GET方法

ab -n 100 -c 100 https://www.baidu.com/index.html
-n:請求 總數
-c:併發使用者數.
-url:待測api。
當測試發起請求數量較少,完成較快,無中間過程顯示。在請求數量很多時會分行顯示當前完成數量。

2.1.2 POST方法

ab -n 10 -c 1 -T 'application/x-www-form-urlencoded'  -p ./post http://172.28.28.17:3017/oauth2/token

-T: Post http header型別 預設為text/plain
-P:Post body內容, ab要求寫在檔案中,-p後跟檔案目錄,檔案內容如name=hello&password=1234

2.1.3 測試結果解讀

我們主要關注的輸出資訊為:

  • Concurrency Level: 10 //併發級別,也就是併發數,請求中-c引數指定的數量
  • Time taken for tests: 1.093 seconds //本次測試總共花費的時間
  • Complete requests: 100 //本次測試總共發起的請求數量
  • Failed requests: 0 //失敗的請求數量。因網路原因或伺服器效能原因,發起的請求並不一定全部成功,通過該數值和Complete requests相除可以計算請求的失敗率,作為測試結果的重要參考。
  • Total transferred: 103314 bytes //總共傳輸的資料量,指的是ab從被測伺服器接收到的總資料量,包括index.html的文字內容和請求頭資訊。
  • Requests per second: 91.50 [#/sec] (mean) //平均(mean)每秒完成的請求數:QPS,這是一個平均值,等於Complete requests/Time taken for tests=100/1.093=91.50
  • Time per request: 109.287 [ms] (mean) //從使用者角度看,完成一個請求所需要的時間(因使用者數量不止一個,伺服器完成10個請求,平均每個使用者才接收到一個完整的返回,所以該值是下一項數值的10倍。)
  • Time per request: 10.929 [ms] (mean, across all concurrent requests)// 伺服器完成一個請求的時間。
  • Transfer rate: 92.32 [Kbytes/sec] received  //網路傳輸速度。對於大檔案的請求測試,這個值很容易成為系統瓶頸所在。要確定該值是不是瓶頸,需要了解客戶端和被測伺服器之間的網路情況,包括網路頻寬和網絡卡速度等資訊。

其中我們最為關注的為Requests per second: 即tps。我們將它最為伺服器效能最為重要的指標。

2.2伺服器端檢測方法

可以通過 iftop命令和nethogs -d 對伺服器網路情況進行檢測。
可以通過iptables命令監控伺服器埠流量。
可以通過 top | grep “node” 對記憶體和cpu進行判斷。
對雲上測試 可以使用雲主機後臺,但後臺引數是分鐘級後的平均值。
感覺好像這樣測優點蠢

3 實際測試

使用apacheBench 可以使用編寫shell指令碼進行多次測試。可以將待測api 放入api陣列並修改迴圈數量,實現一次測試多個api並生成關鍵引數xls檔案。現在看來還是原來太天真才會有這種想法。

3.1 shell指令碼

使用說明:a 是請求總數 ,b是併發使用者數一一對應,即a[0]對應b[0],傳入引數第一個是待測api伺服器地址,第二個是api所需引數。api設定在api陣列中。新增多個api 或同意api多組測試請修改迴圈計數。

echo "you maybe use this sh like:"$0" serverIP userParam"
a=(1000 2000 4000 6000 7000)#待測請求總數
b=(50 100 200 300 400)#併發使用者數
runTime=$(date +%Y%m%d%H%M%S)

if [ -z "$1"]
then
	serverip="http://127.0.0.1"
else
	serverip=$1
fi

if [ -z "$2"]
then
	param="deviceid=XXX&bindingplatform=XXX&bindingid=XXX"
else
	param=$2
fi

filename=${runTime}"-test.log"
touch filename

#api=('XXX'${param} 'XXX'${param} '/users/account')
api=('XXX'${param})
echo "********webserver test info*************"
echo "testTime :"$(date) 
echo "LogName  :"${filename}
echo "serverIP :"${serverip}
echo "userparam:"${param}
echo "********webserver test info*************" 
#echo ${filename}

for j in {0..0}#待測api個數 即api陣列數
do
	echo "API test:"${serverip}${api[j]}
	for i in {0..4}#待測api測試次數 5次也就是對應a b陣列有個五個值
	do
		ab -r -k -n ${a[i]} -c ${b[i]} -C ${param} ${serverip}${api[j]} | grep -e"Document Path:" -e "Complete requests:" -e "Concurrency Level:" -e"Failed requests:" -e"Time taken for tests:" -e "Requests per second:" -e "Time per request" -e"Total transferred: " >> ${filename}
	done
done
sed -i 's/^.\{24\}//g' ${filename}# 按照時間生成txt檔案 並按上面的引數進行提取。
export LD_LIBRARY_PATH=
./change ${filename} ${runTime}"report.xls"#chang 函式功能是將txt中關鍵資料變成xls檔案。
rm ${filename} 

3.2 C++提取程式:使用了libxl.h

#include <iostream>
#include <fstream>
#include <string>
#include "libxl.h"
using namespace std;
using namespace libxl;
int main(int agrc, char *argc[])
{

	//cout << "helloworld" << endl;
	fstream f;
	ifstream ifile(argc[1]);
	string temp;
	int i = 0, j=1, k = 0;

	Book* book = xlCreateBook();//建立一個二進位制格式的XLS(Execl97-03)的例項,在使用前必須先呼叫這個函式建立操作excel的物件
	//book->setKey(......);//如果購買了該庫,則設定相應的key,若沒有購買,則不用這行
	if (book)//是否建立例項成功
	{

		Sheet* sheet = book->addSheet("Sheet1");//新增一個工作表
		
		for(i=0;i<30;i++)
		{
			for(j=0;j<10;j++){
				sheet->setCol(i, j, 20);//設定列寬,格式等
			}
		}
		i=0;
		j=1;
		
		if (sheet)
		{
			sheet->writeStr(j, 0, "API");
			sheet->writeStr(j, 1, "Concurrency Level");
			sheet->writeStr(j, 2, "Time taken for tests");
			sheet->writeStr(j, 3, "Complete requests");
			sheet->writeStr(j, 4, "Failed requests");
			sheet->writeStr(j, 5, "Total transferred");
			sheet->writeStr(j, 6, "Requests per second");
			sheet->writeStr(j, 7, "Time per reques(user)");
			sheet->writeStr(j, 8, "Time per reques(server)");
			j++;
			while (getline(ifile, temp))
			{
				if (temp[0] == '/'){
					f << temp << " ";
					sheet->writeStr(j, i, temp.c_str());
				}
				else if (temp.find('[') != string::npos){
	
					f << temp.substr(0, temp.find('[') - 1) << " ";
					sheet->writeStr(j, i, temp.substr(0, temp.find('[') - 1).c_str());
				}
				else if (temp.find('b') != string::npos){
	
					f << temp.substr(0, temp.find('b') - 1) << " ";
					sheet->writeStr(j, i, temp.substr(0, temp.find('b') - 1).c_str());
				}
				else if (temp.find('s') != string::npos){
					sheet->writeStr(j, i, temp.substr(0, temp.find('s') - 1).c_str());
					f << temp.substr(0, temp.find('s') - 1) << " ";
				}
				else{
					sheet->writeStr(j, i, temp.c_str());
					f << temp << " ";
				}
				i++;
				if (i == 9){
					f << " " << endl;
					i = 0;
					j++;
				}
			}
			ifile.close();
		}
		if (book->save(argc[2]))//儲存到example.xls
		{
			//.....
		}
		else
		{
			std::cout << book->errorMessage() << std::endl;
		}
		book->release();}
	return 0;
}

3.3測試結果xls截圖:

4 測試中遇到一些問題

在本地一般制約tps的因素為cpu。
在雲上測試遇到主要限制因素則是頻寬。
ab軟體中Total transferred 與埠流量有差距。埠流量大於Total transferred,猜測是有封包的因素。所以不能把Total transferred作為伺服器消耗的流量來處理,用於計算雲上某些按流量消耗的服務。