壓力測試webbench

來源:互聯網
上載者:User

標籤:style   blog   http   io   ar   os   使用   sp   for   

最近app需要搭建後台,故此研究一下,靠譜的後台伺服器..網傳nginx 能達到的並發數量比apache 高. LAMP or LNMP ? 根據需求測試結果來進行選擇。

首先是安裝LNMP測試完後 再測試 LAMP,網上很多,我這裡就介紹一下自己在ubuntu 安裝webbench(壓力測試工具)http://home.tiscali.cz/~cz210552/webbench.html

1.下載webbench 

[email protected]:~$ wget http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.gz

2.解壓安裝webbench

[email protected]:~/Downloads$ tar -zxvf webbench-1.5.tar.gz

[email protected]:~/Downloads$ cd webbench-1.5/
[email protected]:~/Downloads/webbench-1.5$ make && make install

可能會遇到許可權問題和ctags命令解析不了問題:

make: [tags] Error 127 (ignored)
install -s webbench /usr/local/bin
install: cannot create regular file `/usr/local/bin/webbench‘: Permission denied

解決方案:

(1).修改相應目錄的許可權

[email protected]:/usr$ sudo chmod a+w -R local/

(2) 安裝 ctags命令

[email protected]:~/Downloads/webbench-1.5$ sudo apt-get install ctags

(3)安裝make

[email protected]:~/Downloads/webbench-1.5$ sudo make && make install

3.接下來可以測試了

 

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

條件1:類比200個用戶端請求.

[email protected]:~/Downloads/webbench-1.5$ webbench -c 200 -t 60 http://127.0.0.1/index.php (-c 時間同時並發串連數,-t是請求持續的時間)
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://127.0.0.1/index.php
200 clients, running 60 sec.

Speed=61325 pages/min, 164563 bytes/sec.
Requests: 61325 susceed, 0 failed.

結果1:伺服器響應 1022 page /sec,61325請求全部成功

 

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

請求2: 500 個用戶端並發請求,流暢

[email protected]:~/Downloads/webbench-1.5$ webbench -c 500 -t 60 http://127.0.0.1/index.phpWebbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://127.0.0.1/index.php
500 clients, running 60 sec.

Speed=48949 pages/min, 133143 bytes/sec.
Requests: 48949 susceed, 0 failed.

結果2:48949 pages/min, 133143 bytes/sec   ,響應順利

 

 

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

請求3:1000個用戶端並發請求

[email protected]:~/Downloads/webbench-1.5$ webbench -c 1000 -t 60 http://127.0.0.1/index.php
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.


Benchmarking: GET http://127.0.0.1/index.php
1000 clients, running 60 sec.


Speed=18342 pages/min, 52711 bytes/sec.
Requests: 18309 susceed, 33 failed.

 

結果3:響應延遲,並有失敗現象

 

 

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

請求4:2000個用戶端並發請求

[email protected]:~/Downloads/webbench-1.5$ webbench -c 2000 -t 60 http://127.0.0.1/index.php

Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.


Benchmarking: GET http://127.0.0.1/index.php
2000 clients, running 60 sec.


Speed=585724 pages/min, 125593 bytes/sec.
Requests: 584688 susceed, 1036 failed.

結果4:失敗數增多

----------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

請求5:10000個用戶端並發請求

[email protected]:~/Downloads/webbench-1.5$ webbench -c 10000 -t 60 http://127.0.0.1/index.php
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.


Benchmarking: GET http://127.0.0.1/index.php
10000 clients, running 60 sec.
problems forking worker no. 7762
fork failed.: Resource temporarily unavailable

結果5:伺服器掛了

----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

關於webbench源碼的分析(轉)

 

一、我與webbench二三事

 

Webbench是一個在linux下使用的非常簡單的網站壓測工具。它使用fork()類比多個用戶端同時訪問我們設定的URL,測試網站在壓力下工作的效能。Webbench使用C語言編寫,下面是其下載連結:

 

http://home.tiscali.cz/~cz210552/webbench.html

 

說到這裡,我趕腳非常有必要給這個網站局部一個,如:

 

 

第一次看到這張圖片,著實吃了一精!居然是2004年最後一次更新,我和我的小夥伴們都驚呆了。不過既然現在大家還都使用,其中一定有些很通用的思想,所以我不妨學習一下,也能為以後的工具開發做鋪墊。當然,另外一個讓我衝動地想研究一下的原因是,webbench的代碼實在太簡潔了,源碼加起來不到600行……

 

把webbench-1.5.tar.gz這個檔案下載下來之後解壓縮,進入webbench-1.5檔案夾,然後執行make,就可以看到檔案夾下多了一個可執行程式webbench。嘗試運行一下,就可以得到的結果。

 

 

可以看到,我們類比了10個client同時訪問URL所示的某個圖片,測試執行了5秒。最終得到的結果是,我們發送http GET請求的速度為188892pages/min,伺服器響應速度為5518794bytes/sec,請求中有15741個成功,0個失敗。

 

大概知道了怎麼用以後,我們就可以深入瞭解其原始碼了。

 

二、與webbench的初步相識

 

我們首先來看一下webbench的工作流程,如:

 

 

 

webbench主要的工作原理就是以下幾點:

 

1. 主函數進行必要的準備工作,進入bench開始壓測

 

2. bench函數使用fork類比出多個用戶端,調用socket並發請求,每個子進程記錄自己的訪問資料,並寫入管道

 

3. 父進程從管道讀取子進程的輸出資訊

 

4. 使用alarm函數進行時間控制,到時間後會產生SIGALRM訊號,調用訊號處理函數使子進程停止

 

5. 最後只留下父進程將所有子進程的輸出資料匯總計算,輸出到螢幕上

 

三、走進webbench的內心世界

 

接下來我們詳細webbench的原始碼。查看webbench的原始碼,發現代碼檔案只有兩個,Socket.c和webbench.c。首先看一下Socket.c,它當中只有一個函數int Socket(const char *host, int clientPort),大致內容如下:

 

int Socket(const char *host, int clientPort){    //以host為伺服器端ip,clientPort為伺服器連接埠號碼建立socket串連    //連線類型為TCP,使用IPv4網域    //一旦出錯,返回-1    //正常串連,則返回socket描述符}

 

 這段代碼比較直觀,因此就不列舉其中的細節了。此函數供另外一個檔案webbench.c中的函數調用。

 

接著我們來瞧一下webbench.c檔案。這個檔案中包含了以下幾個函數,我們一一列舉出來:

 

static void alarm_handler(int signal); //為方便下文引用,我們稱之為函數1。static void usage(void); //函數2void build_request(const char *url); //函數3static int bench(void); //函數4void benchcore(const char *host, const int port, const char *req); //函數5int main(int argc, char *argv[]); //函數6

 

 下面我們分別做講解。

 

(1)全域變數列表

 

源檔案中出現在所有函數前面的全域變數,主要有以下幾項,我們以注釋的方式解釋其在程式中的用途

 

volatile int timerexpired=0;//判斷壓測時間長度是否已經到達設定的時間int speed=0; //記錄進程成功得到伺服器響應的數量int failed=0;//記錄失敗的數量(speed表示成功數,failed表示失敗數)int bytes=0;//記錄進程成功讀取的位元組數int http10=1;//http版本,0表示http0.9,1表示http1.0,2表示http1.1int method=METHOD_GET; //預設請求方式為GET,也支援HEAD、OPTIONS、TRACEint clients=1;//並發數目,預設只有1個進程發請求,通過-c參數設定int force=0;//是否需要等待讀取從server返回的資料,0表示要等待讀取int force_reload=0;//是否使用緩衝,1表示不緩衝,0表示可以快取頁面面int proxyport=80; //Proxy 伺服器的連接埠char *proxyhost=NULL; //Proxy 伺服器的ipint benchtime=30; //壓測時間,預設30秒,通過-t參數設定int mypipe[2]; //使用管道進行父進程和子進程的通訊char host[MAXHOSTNAMELEN]; //伺服器端ipchar request[REQUEST_SIZE]; //所要發送的http請求

 

(2)函數1: static void alarm_handler(int signal);

 

首先,來看一下最簡單的函數,即函數1,它的內容如下:

 

static void alarm_handler(int signal){   timerexpired=1;}

 

 webbench在運行時可以設定壓測的期間,以秒為單位。例如我們希望測試30秒,也就意味著壓測30秒後程式應該退出了。webbench中使用訊號(signal)來控製程序結束。函數1是在到達結束時間時啟動並執行訊號處理函數。它僅僅是將一個記錄是否逾時的變數timerexpired標記為true。後面會看到,在程式的while迴圈中會不斷檢測此值,只有timerexpired=1,程式才會跳出while迴圈並返回。

 

(3)函數2 :static void usage(void);

 

其內容如下:

 

static void usage(void){   fprintf(stderr,    "webbench [option]... URL\n"    "  -f|--force               Don‘t wait for reply from server.\n"    "  -r|--reload              Send reload request - Pragma: no-cache.\n"    "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"    "  -p|--proxy <server:port> Use proxy server for request.\n"    "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"    "  -9|--http09              Use HTTP/0.9 style requests.\n"    "  -1|--http10              Use HTTP/1.0 protocol.\n"    "  -2|--http11              Use HTTP/1.1 protocol.\n"    "  --get                    Use GET request method.\n"    "  --head                   Use HEAD request method.\n"    "  --options                Use OPTIONS request method.\n"    "  --trace                  Use TRACE request method.\n"    "  -?|-h|--help             This information.\n"    "  -V|--version             Display program version.\n"    );};

 

 從名字來看就很明顯,這是教你如何使用webbench的函數,在linux命令列調用webbench方法不對的時候運行,作為提示。有一些比較常用的,比如-c來指定並發進程的多少;-t指定壓測的時間,以秒為單位;支援HTTP0.9,HTTP1.0,HTTP1.1三個版本;支援GET,HEAD,OPTIONS,TRACE四種請求方式。不要忘了調用時,命令列最後還應該附上要測的服務端URL。

 

(4)函數3:void build_request(const char *url);

 

這個函數主要操作全域變數char request[REQUEST_SIZE],根據url填充其內容。一個典型的http GET請求如下:

 

GET /test.jpg HTTP/1.1User-Agent: WebBench 1.5Host:192.168.10.1Pragma: no-cacheConnection: close

 

build_request函數的目的就是要把類似於以上這一大坨資訊全部存到全域變數request[REQUEST_SIZE]中,其中換行操作使用的是”\r\n”。而以上這一大坨資訊的具體內容是要根據命令列輸入的參數,以及url來確定的。該函數使用了大量的字串操作函數,例如strcpy,strstr,strncasecmp,strlen,strchr,index,strncpy,strcat。對這些基礎函數不太熟悉的同學可以借這個函數複習一下。build_request的具體內容在此不做過多闡述。

 

(5)函數6:int main(int argc, char *argv[]);

 

之所以把函數6放在了函數4和函數5之前,是因為函數4和5是整個工具的最核心代碼,我們把他放在最後分析。先來看一下整個程式的起始點:主函數(即函數6)。

 

int main(int argc, char *argv[]){    /*函數最開始,使用getopt_long函數讀取命令列參數,    來設定(1)中所提及的全域變數的值。    關於getopt_long的具體使用方法,這裡有一個配有講解的小例子,可以協助學習:    http://blog.csdn.net/lanyan822/article/details/7692013    在此期間如果出現錯誤,會調用函數2告知使用者此工具使用方法,然後退出。    */        build_request(argv[optind]); //參數讀完後,argv[optind]即放在命令列最後的url                              //調用函數3建立完整的HTTP request,                            //HTTP request儲存在全部變數char request[REQUEST_SIZE]        /*接下來的部分,main函數的所有代碼都是在網螢幕上列印此次測試的資訊,    例如即將測試多少秒,幾個並發進程,使用哪個HTTP版本等。    這些資訊並非程式核心代碼,因此我們也略去。    */        return bench(); //簡簡單單一句話,原來,壓力測試在這最後一句才真正開始!                 //所有的壓測都在bench函數(即函數4)實現}

 

 這真是一件很浪費感情的事情,看了半天,一直到最後一句才開始執行真正的測試過程,前面的都是一些準備工作。好了,那我們現在開始進入到static int bench(void)中。

 

(6)函數4:static int bench(void);

 

源碼如下:

 

static int bench(void){  int i,j,k;      pid_t pid=0;  FILE *f;    i=Socket(proxyhost==NULL?host:proxyhost,proxyport); //調用了Socket.c檔案中的函數  if(i<0){ /*錯誤處理*/ }  close(i);  if(pipe(mypipe)){ /*錯誤處理*/ } //管道用於子進程向父進程回報資料  for(i=0;i<clients;i++){//根據clients大小fork出來足夠的子進程進行測試       pid=fork();       if(pid <= (pid_t) 0){           sleep(1); /* make childs faster */           break;       }  }  if( pid< (pid_t) 0){ /*錯誤處理*/ }  if(pid== (pid_t) 0){//如果是子進程,調用benchcore進行測試    if(proxyhost==NULL)      benchcore(host,proxyport,request);    else      benchcore(proxyhost,proxyport,request);     f=fdopen(mypipe[1],"w");//子進程將測試結果輸出到管道     if(f==NULL){ /*錯誤處理*/ }     fprintf(f,"%d %d %d\n",speed,failed,bytes);     fclose(f);     return 0;  } else{//如果是父進程,則從管道讀取子進程輸出,並作匯總     f=fdopen(mypipe[0],"r");      if(f==NULL) { /*錯誤處理*/ }      setvbuf(f,NULL,_IONBF,0);      speed=0;  failed=0;  bytes=0;      while(1){ //從管道讀取資料,fscanf為阻塞式函數          pid=fscanf(f,"%d %d %d",&i,&j,&k);          if(pid<2){ /*錯誤處理*/ }          speed+=i;  failed+=j;  bytes+=k;          if(--clients==0) break;//這句用於記錄已經讀了多少個子進程的資料,讀完就退出      }      fclose(f);    //最後將結果列印到螢幕上     printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n",          (int)((speed+failed)/(benchtime/60.0f)), (int)(bytes/(float)benchtime), speed, failed);  }  return i;}

 

 這段代碼,一上來先進行了一次socket串連,確認能連通以後,才進行後續步驟。調用pipe函數初始化一個管道,用於子進行向父進程彙報測試資料。子進程根據clients數量fork出來。每個子進程都調用函數5進行測試,並將結果輸出到管道,供父進程讀取。父進程負責收集所有子進程的測試資料,並匯總輸出。

 

(7)函數5:void benchcore(const char *host,const int port,const char *req);

 

源碼如下:

 

void benchcore(const char *host,const int port,const char *req){ int rlen; char buf[1500];//記錄伺服器響應請求所返回的資料 int s,i; struct sigaction sa; sa.sa_handler=alarm_handler; //設定函數1為訊號處理函數 sa.sa_flags=0; if(sigaction(SIGALRM,&sa,NULL)) //逾時會產生訊號SIGALRM,用sa中的指定函數處理    exit(3);   alarm(benchtime);//開始計時 rlen=strlen(req); nexttry:while(1){    if(timerexpired){//一旦逾時則返回       if(failed>0){failed--;}       return;    }    s=Socket(host,port);//調用Socket函數建立TCP串連    if(s<0) { failed++;continue;}     if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;} //發出請求      if(http10==0) //針對http0.9做的特殊處理        if(shutdown(s,1)) { failed++;close(s);continue;}        if(force==0){//全域變數force表示是否要等待伺服器返回的資料        while(1){        if(timerexpired) break;          i=read(s,buf,1500);//從socket讀取返回資料          if(i<0) {           failed++;          close(s);          goto nexttry;        }else{          if(i==0) break;            else              bytes+=i;        }        }    }    if(close(s)) {failed++;continue;}    speed++; }}

 

 benchcore是子進程進行壓力測試的函數,被每個子進程調用。這裡使用了SIGALRM訊號來控制時間,alarm函數設定了多少時間之後產生SIGALRM訊號,一旦產生此訊號,將運行函數1,使得timerexpired=1,這樣可以通過判斷timerexpired值來退出程式。另外,全域變數force表示我們是否在發出請求後需要等待伺服器的響應結果。

 

四、昨天,今天,明天

 

瞭解了webbench的具體代碼以後,下面一步就要考慮一下如何進行改進了。代碼中有一些過時的函數可以更新一下,加入一些新的功能,例如支援POST方法,支援非同步壓測等,這些就留到以後去探索了。第一次寫源碼分析,望多多指教。希望本文能協助大家在以後與webbench愉快地玩耍。且用且珍惜!

 

壓力測試webbench(轉)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.