1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > web性能压力测试工具:WebBench详解

web性能压力测试工具:WebBench详解

时间:2024-03-26 06:44:07

相关推荐

web性能压力测试工具:WebBench详解

1.Webbench官方主页:

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

Webbench的官方介绍:

Web Bench is very simple tool for benchmarking WWW or proxy servers. Usesfork()for simulating multiple clients and can use HTTP/0.9-HTTP/1.1 requests. This benchmark is not very realistic, but it can test if your HTTPD can realy handle that many clients at once (try to run some CGIs) without taking your machine down. Displays pages/min and bytes/sec. Can be used in more aggressive mode with -f switch.

Webbench能测试处在相同硬件上,不同服务的性能,也能测试不同硬件上同一个服务的运行状况。webbench的标准测试可以展示服务器的两项内容:每秒钟相应请求数和每秒钟传输数据量。webbench具有静态页面的测试能力,能对动态页面(ASP,PHP,JAVA,CGI)进行测试;也支持对含有SSL的安全网站例如电子商务网站进行静态或动态的性能测试

2. webbench在运维工作中的作用:

压力测试在运维工作中有重要的作用。在一个网站上线之前,能承受的访问量、在高并发访问情况下的性能怎样,这些数据指标直接体现了系统的性能,压力测试可以给开发者一个对产品质量的评估。

但是,压力测试的结果与实际负载结果不会完全相同,就算压力测试工作做的再好,也不能保证100%和线上性能指标相同。面对这些问题,我们只能尽量去想方设法去模拟。所以,压力测试非常有必要,有了这些数据,我们就能对自己做维护的平台做到心中有数。

3.Webbench的使用:

一般用到-c和-t两个参数:

像下面的例子可测试百度网站的性能情况:

webbench -c 300 -t 60 /

-t表示测试的时间,-c表示并发访问网站的客户数。

测试运行的结果如下:

返回的结果中有两个指标:

pages/min:每分输出的页面数;bytes/sec:每秒传输的比特数;succeed和failed表示请求的成功数目和失败数目;

4.webbench的源码分析:

项目的源代码位于socket.c和webbench.c文件中,其他文档都是说明文档和用户编译的文档。

项目中涉及的知识点有:命令行参数解析(getopt_long)、信号处理(sigaction)、socket管道读写。

项目主要函数:

main提供程序的入口;build_request构造HTTP请求;bench派生子进程,父子进程间通过管道通信最后输出计算结果;benchcore负责每个进程实际发起请求;alarm_handler负责信号处理,在时钟结束时调用;usage输出webbench命令的具体参数;

项目主要流程:

1. 解析命令行参数,根据命令行指定参数设定变量,可以认为是初始化配置。

2.根据指定的配置构造 HTTP 请求报文格式。

3.开始执行 bench 函数,先进行一次 socket 连接建立与断开,测试是否可以正常访问。

4.建立管道,派生根据指定进程数派生子进程。

5.每个子进程调用 benchcore 函数,先通过sigaction 安装信号,用 alarm 设置闹钟函数,接着不断建立 socket 进行通信,与服务器交互数据,直到收到信号结束访问测试。子进程将访问测试结果写进管道。

6.父进程读取管道数据,汇总子进程信息,收到所有子进程消息后,输出汇总信息,结束。

流程图:

项目源码:

webbench.c:

/** (C) Radim Kolar 1997-* This is free software, see GNU Public License version 2 for* details.** Simple forking WWW Server benchmark:** Usage:* webbench --help** Return codes:* 0 - sucess* 1 - benchmark failed (server is not on-line)* 2 - bad param* 3 - internal error, fork failed* */ #include "socket.c"#include <unistd.h>#include <sys/param.h>#include <rpc/types.h>#include <getopt.h>#include <strings.h>#include <time.h>#include <signal.h>/* values */volatile int timerexpired=0;int speed=0;int failed=0;int bytes=0;/* globals */int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 *//* Allow: GET, HEAD, OPTIONS, TRACE */#define METHOD_GET 0#define METHOD_HEAD 1#define METHOD_OPTIONS 2#define METHOD_TRACE 3#define PROGRAM_VERSION "1.5"int method=METHOD_GET; //GET方式int clients=1; //仅模拟一个客户端int force=0; //等待响应int force_reload=0; //失败时重新请求int proxyport=80;//访问端口char *proxyhost=NULL; //代理服务器int benchtime=30;//模拟请求时间/* internal */int mypipe[2]; //管道char host[MAXHOSTNAMELEN]; //网络地址#define REQUEST_SIZE 2048char request[REQUEST_SIZE]; //请求static const struct option long_options[]={{"force",no_argument,&force,1},{"reload",no_argument,&force_reload,1},{"time",required_argument,NULL,'t'},{"help",no_argument,NULL,'?'},{"http09",no_argument,NULL,'9'},{"http10",no_argument,NULL,'1'},{"http11",no_argument,NULL,'2'},{"get",no_argument,&method,METHOD_GET},{"head",no_argument,&method,METHOD_HEAD},{"options",no_argument,&method,METHOD_OPTIONS},{"trace",no_argument,&method,METHOD_TRACE},{"version",no_argument,NULL,'V'},{"proxy",required_argument,NULL,'p'},{"clients",required_argument,NULL,'c'},{NULL,0,NULL,0}};/* prototypes */static void benchcore(const char* host,const int port, const char *request);static int bench(void);static void build_request(const char *url);static void alarm_handler(int signal){timerexpired=1;}static void usage(void){fprintf(stderr,"webbench [option]... URL\n"" -f|--forceDon'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"" --getUse GET request method.\n"" --head Use HEAD request method.\n"" --optionsUse OPTIONS request method.\n"" --trace Use TRACE request method.\n"" -?|-h|--help This information.\n"" -V|--version Display program version.\n");}int main(int argc, char *argv[]){int opt=0;int options_index=0;char *tmp=NULL;//不带参数时,直接输出help信息if(argc==1){usage();return 2;} //getopt_long为命令行解析的库函数while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF ){switch(opt){case 0 : break;case 'f': force=1;break;case 'r': force_reload=1;break; case '9': http10=0;break;case '1': http10=1;break;case '2': http10=2;break;case 'V': printf(PROGRAM_VERSION"\n");exit(0);case 't': benchtime=atoi(optarg);break;case 'p': /* proxy server parsing server:port */tmp=strrchr(optarg,':');proxyhost=optarg;if(tmp==NULL){break;}if(tmp==optarg){fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);return 2;}if(tmp==optarg+strlen(optarg)-1){fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);return 2;}*tmp='\0';proxyport=atoi(tmp+1);break;case ':':case 'h':case '?': usage();return 2;break;case 'c': clients=atoi(optarg);break;}}//optind被getopt_long设置为命令行参数中未读物的下一个元素下标值if(optind==argc) {fprintf(stderr,"webbench: Missing URL!\n");usage();return 2;}//不能指定客户端数和请求时间为0if(clients==0) clients=1;if(benchtime==0) benchtime=30;/* Copyright */fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n""Copyright (c) Radim Kolar 1997-, GPL Open Source Software.\n");//构造HTTP请求到request数组build_request(argv[optind]);// print request info ,do it in function build_request/*printf("Benchmarking: ");switch(method){case METHOD_GET:default:printf("GET");break;case METHOD_OPTIONS:printf("OPTIONS");break;case METHOD_HEAD:printf("HEAD");break;case METHOD_TRACE:printf("TRACE");break;}printf(" %s",argv[optind]);switch(http10){case 0: printf(" (using HTTP/0.9)");break;case 2: printf(" (using HTTP/1.1)");break;}printf("\n");*/printf("Runing info: ");if(clients==1) printf("1 client");elseprintf("%d clients",clients);printf(", running %d sec", benchtime);if(force) printf(", early socket close");if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport);if(force_reload) printf(", forcing reload");printf(".\n");//开始压力测试return bench();}void build_request(const char *url){char tmp[10];int i;//bzero(host,MAXHOSTNAMELEN);//bzero(request,REQUEST_SIZE);memset(host,0,MAXHOSTNAMELEN);memset(request,0,REQUEST_SIZE);//判断应该使用的HTTP协议if(force_reload && proxyhost!=NULL && http10<1) http10=1;if(method==METHOD_HEAD && http10<1) http10=1;if(method==METHOD_OPTIONS && http10<2) http10=2;if(method==METHOD_TRACE && http10<2) http10=2;//填写method方法switch(method){default:case METHOD_GET: strcpy(request,"GET");break;case METHOD_HEAD: strcpy(request,"HEAD");break;case METHOD_OPTIONS: strcpy(request,"OPTIONS");break;case METHOD_TRACE: strcpy(request,"TRACE");break;}strcat(request," ");//url合法性判断if(NULL==strstr(url,"://")){fprintf(stderr, "\n%s: is not a valid URL.\n",url);exit(2);}if(strlen(url)>1500){fprintf(stderr,"URL is too long.\n");exit(2);}if (0!=strncasecmp("http://",url,7)) { //仅支持HTTP协议fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");exit(2);}//找到主机名开始的地方/* protocol/host delimiter */i=strstr(url,"://")-url+3;//必须以/结束if(strchr(url+i,'/')==NULL) {fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");exit(2);}if(proxyhost==NULL){/* get port from hostname */if(index(url+i,':')!=NULL && index(url+i,':')<index(url+i,'/')){strncpy(host,url+i,strchr(url+i,':')-url-i);//bzero(tmp,10);memset(tmp,0,10);strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);/* printf("tmp=%s\n",tmp); *///设置端口proxyport=atoi(tmp);if(proxyport==0) proxyport=80;} else{strncpy(host,url+i,strcspn(url+i,"/"));}// printf("Host=%s\n",host);strcat(request+strlen(request),url+i+strcspn(url+i,"/"));} else{// printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport);strcat(request,url);}if(http10==1)strcat(request," HTTP/1.0");else if (http10==2)strcat(request," HTTP/1.1");strcat(request,"\r\n");if(http10>0)strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n");if(proxyhost==NULL && http10>0){strcat(request,"Host: ");strcat(request,host);strcat(request,"\r\n");}if(force_reload && proxyhost!=NULL){strcat(request,"Pragma: no-cache\r\n");}if(http10>1)strcat(request,"Connection: close\r\n");/* add empty line at end */if(http10>0) strcat(request,"\r\n"); printf("\nRequest:\n%s\n",request);}/* vraci system rc error kod */static int bench(void){int i,j,k;pid_t pid=0;FILE *f;/* check avaibility of target server */i=Socket(proxyhost==NULL?host:proxyhost,proxyport);if(i<0) { fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");return 1;}close(i);/* create pipe */if(pipe(mypipe)){perror("pipe failed.");return 3;}/* not needed, since we have alarm() in childrens *//* wait 4 next system clock tick *//*cas=time(NULL);while(time(NULL)==cas)sched_yield();*//* fork childs *///派生子进程for(i=0;i<clients;i++){pid=fork();if(pid <= (pid_t) 0){/* child process or error*/sleep(1); /* make childs faster */break;}}if( pid < (pid_t) 0){fprintf(stderr,"problems forking worker no. %d\n",i);perror("fork failed.");return 3;}if(pid == (pid_t) 0){/* I am a child *///子进程发出实际请求if(proxyhost==NULL)benchcore(host,proxyport,request);elsebenchcore(proxyhost,proxyport,request);/* write results to pipe *///打开管道写f=fdopen(mypipe[1],"w");if(f==NULL){perror("open pipe for writing failed.");return 3;}/* fprintf(stderr,"Child - %d %d\n",speed,failed); */fprintf(f,"%d %d %d\n",speed,failed,bytes);fclose(f);return 0;} else{//父进程打开管道读f=fdopen(mypipe[0],"r");if(f==NULL) {perror("open pipe for reading failed.");return 3;}setvbuf(f,NULL,_IONBF,0);speed=0;//传输速度failed=0;//失败请求数bytes=0;//传输字节数while(1){pid=fscanf(f,"%d %d %d",&i,&j,&k);if(pid<2){fprintf(stderr,"Some of our childrens died.\n");break;}speed+=i;failed+=j;bytes+=k;/* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); *///子进程是否读取完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;}void benchcore(const char *host,const int port,const char *req){int rlen;char buf[1500];int s,i;struct sigaction sa;/* setup alarm signal handler *///安装信号sa.sa_handler=alarm_handler;sa.sa_flags=0;if(sigaction(SIGALRM,&sa,NULL))exit(3);//设置闹钟函数alarm(benchtime); // after benchtime,then exitrlen=strlen(req);/* 收到信号则 timerexpired = 1 */nexttry:while(1){if(timerexpired){if(failed>0){/* fprintf(stderr,"Correcting failed by signal\n"); */failed--;}return;}//建立socket,进行http请求s=Socket(host,port);if(s<0) { failed++;continue;} if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;}if(http10==0) if(shutdown(s,1)) { failed++;close(s);continue;}if(force==0) {/* read all available data from socket */while(1){if(timerexpired) break; i=read(s,buf,1500);/* fprintf(stderr,"%d\n",i); */if(i<0) { failed++;close(s);goto nexttry;}elseif(i==0) break;elsebytes+=i;}}if(close(s)) {failed++;continue;}speed++;}}

socket.c源码:

/* $Id: socket.c 1.1 1995/01/01 07:11:14 cthuang Exp $** This module has been modified by Radim Kolar for OS/2 emx*//***********************************************************************module: socket.cprogram:popclientSCCS ID:@(#)socket.c 1.5 4/1/94programmer: Virginia Tech Computing Centercompiler:DEC RISC C compiler (Ultrix 4.1)environment: DEC Ultrix 4.3 description: UNIX sockets code.***********************************************************************/#include <sys/types.h>#include <sys/socket.h>#include <fcntl.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <sys/time.h>#include <string.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>int Socket(const char *host, int clientPort){int sock;unsigned long inaddr;struct sockaddr_in ad;struct hostent *hp;//初始化地址memset(&ad, 0, sizeof(ad));ad.sin_family = AF_INET;//主机名转化为数字inaddr = inet_addr(host);if (inaddr != INADDR_NONE)memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));else{//获取IP地址hp = gethostbyname(host);if (hp == NULL)return -1;memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);}ad.sin_port = htons(clientPort);//建立socketsock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0)return sock;//建立连接if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)return -1;return sock;}

参考:

/pony_maggie/article/details/62887547

/pony_maggie/article/details/62887547

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。