ab(apache bench)是web伺服器APACHE自帶的壓力測試工具。它通過模拟多個用戶端同時對web伺服器發起請求,對WEB伺服器的并發性能進行測試。對于一般的伺服器端程式,ab也提供了一種并發性測試的思路。本文将對ab的關鍵邏輯進行分析。ab的源碼可以從http://code.google.com/p/apachebench-standalone/下載下傳。
ab的使用說明如下:
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
-n requests Number of requests to perform
-c concurrency Number of multiple requests to make
-t timelimit Seconds to max. wait for responses
-b windowsize Size of TCP send/receive buffer, in bytes
-p postfile File containing data to POST. Remember also to set -T
-u putfile File containing data to PUT. Remember also to set -T
-T content-type Content-type header for POSTing, eg.
‘application/x-www-form-urlencoded’
Default is ‘text/plain’
-v verbosity How much troubleshooting info to print
-w Print out results in HTML tables
-i Use HEAD instead of GET
-x attributes String to insert as table attributes
-y attributes String to insert as tr attributes
-z attributes String to insert as td or th attributes
-C attribute Add cookie, eg. ‘Apache=1234. (repeatable)
-H attribute Add Arbitrary header line, eg. ‘Accept-Encoding: gzip’
Inserted after all normal header lines. (repeatable)
-A attribute Add Basic WWW Authentication, the attributes
are a colon separated username and password.
-P attribute Add Basic Proxy Authentication, the attributes
are a colon separated username and password.
-X proxy:port Proxyserver and port number to use
-V Print version number and exit
-k Use HTTP KeepAlive feature
-d Do not show percentiles served table.
-S Do not show confidence estimators and warnings.
-g filename Output collected data to gnuplot format file.
-e filename Output CSV file with percentages served
-r Don’t exit on socket receive errors.
-h Display usage information (this message)
-Z ciphersuite Specify SSL/TLS cipher suite (See openssl ciphers)
-f protocol Specify SSL/TLS protocol (SSL3, TLS1, or ALL)
其中,最常用的參數為-n和-c,這兩個參數分别指定了向伺服器發起的請求數量和并發程度。其它參數則主要針對HTTP請求和響應的格式以及ab的輸出方式。
ab的實作依賴于APR(Apache Portable Runtime)庫,該庫對unix平台程式設計接口進行了統一的封裝和擴充,但從名子可以很容易的看出它們之間的對應關系。本文不再贅述。ab在模拟并發通路時并沒有使用多線程,而是使用了一種異步connect+epoll的方式來實作,下文主要對這一過程進行分析。
我們從ab的main方法看起,該方法主要對參數進行解析并設定了一些代表參數的全局變量,最後分别調用了以下方法:
copyright();
test();
apr_pool_destroy(cntxt);
即ab的主要邏輯包含在test方法中。test方法首先進行了一些全局的初始化工作。其中,最重要的一個資料結構是數組struct connection con[c],代表同時存在的c個用戶端連接配接。struct connection的結構如下:
struct connection {
apr_pool_t *ctx;
apr_socket_t *aprsock;
apr_pollfd_t pollfd;
int state;
apr_size_t read;
apr_size_t bread;
apr_size_t rwrite, rwrote;
apr_size_t length;
char cbuff[CBUFFSIZE];
int cbx;
int keepalive;
int gotheader;
apr_time_t start,
connect,
endwrite,
beginread,
done;
int socknum;
int port;
ifdef USE_SSL
SSL *ssl;
endif
};
test方法首先調用start_connect開始c個初始的連接配接
for (i = 0; i < concurrency; i++) {
con[i].socknum = i;
start_connect(&con[i]);
}
start_connect首先建立一個socket端口并将其設定為非阻塞,這樣調用connect時就會立即傳回EINPROGRESS錯誤,但TCP三步握手仍在背景進行。通過這種方式,就可以同時發起多個連接配接,進而模拟多個用戶端請求伺服器的場景。start_connect的主要邏輯如下:
re = apr_connect(sock);
if(re == EINPROGRESS){
将sock加入到epoll的監控清單中,等待連接配接完成
}
else if(re == SUCCESS){
連接配接已完成,調用write_request送出請求,後文将介紹
}
else{
報錯
}
傳回test 方法,在建立完成初始的連接配接之後,test開始使用epoll來監聽連接配接完成、有新的響應資料等事件并進行處理:
do{
do{
status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
}while (status == EINTR);
for(I = 0;I < n;++i){
……
rv = next_fd->rtnevents; //取epoll事件
if ((rv & APR_POLLIN) || (rv & APR_POLLPRI) || (rv & APR_POLLHUP))
read_connection(c); //讀伺服器端的響應資料
if ((rv & APR_POLLERR) || (rv & APR_POLLNVAL)) {
出錯,此時調用start_connect重試連接配接
}
if(rv & ARP_POLLOUT){ //可寫,如果連接配接完成則傳回可寫事件
if(處于CONNECTING狀态){
rv = apr_socket_connect(c->aprsock, destsa); //此時再連接配接應直接傳回
if (rv != APR_SUCCESS) {
重新調用start_connect開始連接配接
}
else{
//連接配接成功
調用write_request發送請求
}
}
}
}
}while(未完成)
上文中提到的write_request和read_connection分别為向伺服器送出請求以及從伺服器讀取響應資料的方法。其中write_request方法會将預先建立好的http請求的内容一次性發送出去;而read_connection則嘗試讀取、解析伺服器端響應并在讀取到EOF後調用close_connection方法關閉目前連接配接。
最後, close_connection方法除了關閉socket端口、記錄結果外,如果請求數未達到要求時還會複用要關閉的struct connection,重新調用start_connect發起連接配接請求,進而推進測試任務。
在一般的作業系統中,單個程序能夠建立的線程數量是有限的。通過使用異步connect的方式代替多線程,ab可以提高用戶端能夠達到的并發程度,進而提高測試能力。雖然ab本身是針對http伺服器的測試工具,但這種設計可以被用來對任何伺服器端程式進行并發性測試。