最近app需要搭建后台,故此研究一下,靠谱的后台服务器..网传nginx 能达到的并发数量比apache 高. LAMP or LNMP ? 根据需求测试结果来进行选择。

首先是安装LNMP测试完后 再测试 LAMP,网上很多,我这里就介绍一下自己在ubuntu 安装webbench(压力测试工具)http://home.tiscali.cz/~cz210552/webbench.html

1.下载webbench

miechal@miechal-ubuntu:~$ wget http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.gz

2.解压安装webbench

miechal@miechal-ubuntu:~/Downloads$ tar -zxvf webbench-1.5.tar.gz

miechal@miechal-ubuntu:~/Downloads$ cd webbench-1.5/
miechal@miechal-ubuntu:~/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).修改相应目录的权限

miechal@miechal-ubuntu:/usr$ sudo chmod a+w -R local/

(2) 安装 ctags命令

miechal@miechal-ubuntu:~/Downloads/webbench-1.5$ sudo apt-get install ctags

(3)安装make

miechal@miechal-ubuntu:~/Downloads/webbench-1.5$ sudo make && make install

3.接下来可以测试了

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

条件1:模拟200个客户端请求.

miechal@miechal-ubuntu:~/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 个客户端并发请求,流畅

miechal@miechal-ubuntu:~/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个客户端并发请求

miechal@miechal-ubuntu:~/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个客户端并发请求

miechal@miechal-ubuntu:~/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个客户端并发请求

miechal@miechal-ubuntu:~/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),大致内容如下:

  1. int Socket(const char *host, int clientPort)
  2. {
  3. //以host为服务器端ip,clientPort为服务器端口号建立socket连接
  4. //连接类型为TCP,使用IPv4网域
  5. //一旦出错,返回-1
  6. //正常连接,则返回socket描述符
  7. }

这段代码比较直观,因此就不列举其中的细节了。此函数供另外一个文件webbench.c中的函数调用。

接着我们来瞧一下webbench.c文件。这个文件中包含了以下几个函数,我们一一列举出来:

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

下面我们分别做讲解。

(1)全局变量列表

源文件中出现在所有函数前面的全局变量,主要有以下几项,我们以注释的方式解释其在程序中的用途

  1. volatile int timerexpired=0;//判断压测时长是否已经到达设定的时间
  2. int speed=0; //记录进程成功得到服务器响应的数量
  3. int failed=0;//记录失败的数量(speed表示成功数,failed表示失败数)
  4. int bytes=0;//记录进程成功读取的字节数
  5. int http10=1;//http版本,0表示http0.9,1表示http1.0,2表示http1.1
  6. int method=METHOD_GET; //默认请求方式为GET,也支持HEAD、OPTIONS、TRACE
  7. int clients=1;//并发数目,默认只有1个进程发请求,通过-c参数设置
  8. int force=0;//是否需要等待读取从server返回的数据,0表示要等待读取
  9. int force_reload=0;//是否使用缓存,1表示不缓存,0表示可以缓存页面
  10. int proxyport=80; //代理服务器的端口
  11. char *proxyhost=NULL; //代理服务器的ip
  12. int benchtime=30; //压测时间,默认30秒,通过-t参数设置
  13. int mypipe[2]; //使用管道进行父进程和子进程的通信
  14. char host[MAXHOSTNAMELEN]; //服务器端ip
  15. char request[REQUEST_SIZE]; //所要发送的http请求

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

首先,来看一下最简单的函数,即函数1,它的内容如下:

  1. static void alarm_handler(int signal)
  2. {
  3. timerexpired=1;
  4. }

webbench在运行时可以设定压测的持续时间,以秒为单位。例如我们希望测试30秒,也就意味着压测30秒后程序应该退出了。webbench中使用信号(signal)来控制程序结束。函数1是在到达结束时间时运行的信号处理函数。它仅仅是将一个记录是否超时的变量timerexpired标记为true。后面会看到,在程序的while循环中会不断检测此值,只有timerexpired=1,程序才会跳出while循环并返回。

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

其内容如下:

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

从名字来看就很明显,这是教你如何使用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请求如下:

  1. GET /test.jpg HTTP/1.1
  2. User-Agent: WebBench 1.5
  3. Host:192.168.10.1
  4. Pragma: no-cache
  5. Connection: 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)。

  1. int main(int argc, char *argv[])
  2. {
  3. /*函数最开始,使用getopt_long函数读取命令行参数,
  4. 来设置(1)中所提及的全局变量的值。
  5. 关于getopt_long的具体使用方法,这里有一个配有讲解的小例子,可以帮助学习:
  6. http://blog.csdn.net/lanyan822/article/details/7692013
  7. 在此期间如果出现错误,会调用函数2告知用户此工具使用方法,然后退出。
  8. */
  9.  
  10. build_request(argv[optind]); //参数读完后,argv[optind]即放在命令行最后的url
  11. //调用函数3建立完整的HTTP request,
  12. //HTTP request存储在全部变量char request[REQUEST_SIZE]
  13.  
  14. /*接下来的部分,main函数的所有代码都是在网屏幕上打印此次测试的信息,
  15. 例如即将测试多少秒,几个并发进程,使用哪个HTTP版本等。
  16. 这些信息并非程序核心代码,因此我们也略去。
  17. */
  18.  
  19. return bench(); //简简单单一句话,原来,压力测试在这最后一句才真正开始!
  20. //所有的压测都在bench函数(即函数4)实现
  21. }

这真是一件很浪费感情的事情,看了半天,一直到最后一句才开始执行真正的测试过程,前面的都是一些准备工作。好了,那我们现在开始进入到static int bench(void)中。

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

源码如下:

  1. static int bench(void){
  2. int i,j,k;
  3. pid_t pid=0;
  4. FILE *f;
  5.  
  6. i=Socket(proxyhost==NULL?host:proxyhost,proxyport); //调用了Socket.c文件中的函数
  7. if(i<0){ /*错误处理*/ }
  8. close(i);
  9.  
  10. if(pipe(mypipe)){ /*错误处理*/ } //管道用于子进程向父进程回报数据
  11. for(i=0;i<clients;i++){//根据clients大小fork出来足够的子进程进行测试
  12. pid=fork();
  13. if(pid <= (pid_t) 0){
  14. sleep(1); /* make childs faster */
  15. break;
  16. }
  17. }
  18. if( pid< (pid_t) 0){ /*错误处理*/ }
  19.  
  20. if(pid== (pid_t) 0){//如果是子进程,调用benchcore进行测试
  21. if(proxyhost==NULL)
  22. benchcore(host,proxyport,request);
  23. else
  24. benchcore(proxyhost,proxyport,request);
  25.  
  26. f=fdopen(mypipe[1],"w");//子进程将测试结果输出到管道
  27. if(f==NULL){ /*错误处理*/ }
  28. fprintf(f,"%d %d %d\n",speed,failed,bytes);
  29. fclose(f);
  30. return 0;
  31. } else{//如果是父进程,则从管道读取子进程输出,并作汇总
  32. f=fdopen(mypipe[0],"r");
  33. if(f==NULL) { /*错误处理*/ }
  34. setvbuf(f,NULL,_IONBF,0);
  35. speed=0; failed=0; bytes=0;
  36.  
  37. while(1){ //从管道读取数据,fscanf为阻塞式函数
  38. pid=fscanf(f,"%d %d %d",&i,&j,&k);
  39. if(pid<2){ /*错误处理*/ }
  40. speed+=i; failed+=j; bytes+=k;
  41. if(--clients==0) break;//这句用于记录已经读了多少个子进程的数据,读完就退出
  42. }
  43. fclose(f);
  44. //最后将结果打印到屏幕上
  45. printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n",
  46. (int)((speed+failed)/(benchtime/60.0f)), (int)(bytes/(float)benchtime), speed, failed);
  47. }
  48. return i;
  49. }

这段代码,一上来先进行了一次socket连接,确认能连通以后,才进行后续步骤。调用pipe函数初始化一个管道,用于子进行向父进程汇报测试数据。子进程根据clients数量fork出来。每个子进程都调用函数5进行测试,并将结果输出到管道,供父进程读取。父进程负责收集所有子进程的测试数据,并汇总输出。

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

源码如下:

  1. void benchcore(const char *host,const int port,const char *req){
  2. int rlen;
  3. char buf[1500];//记录服务器响应请求所返回的数据
  4. int s,i;
  5. struct sigaction sa;
  6.  
  7. sa.sa_handler=alarm_handler; //设置函数1为信号处理函数
  8. sa.sa_flags=0;
  9. if(sigaction(SIGALRM,&sa,NULL)) //超时会产生信号SIGALRM,用sa中的指定函数处理
  10. exit(3);
  11.  
  12. alarm(benchtime);//开始计时
  13. rlen=strlen(req);
  14. nexttry:while(1){
  15. if(timerexpired){//一旦超时则返回
  16. if(failed>0){failed--;}
  17. return;
  18. }
  19. s=Socket(host,port);//调用Socket函数建立TCP连接
  20. if(s<0) { failed++;continue;}
  21. if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;} //发出请求
  22. if(http10==0) //针对http0.9做的特殊处理
  23. if(shutdown(s,1)) { failed++;close(s);continue;}
  24.  
  25. if(force==0){//全局变量force表示是否要等待服务器返回的数据
  26. while(1){
  27. if(timerexpired) break;
  28. i=read(s,buf,1500);//从socket读取返回数据
  29. if(i<0) {
  30. failed++;
  31. close(s);
  32. goto nexttry;
  33. }else{
  34. if(i==0) break;
  35. else
  36. bytes+=i;
  37. }
  38. }
  39. }
  40. if(close(s)) {failed++;continue;}
  41. speed++;
  42. }
  43. }

benchcore是子进程进行压力测试的函数,被每个子进程调用。这里使用了SIGALRM信号来控制时间,alarm函数设置了多少时间之后产生SIGALRM信号,一旦产生此信号,将运行函数1,使得timerexpired=1,这样可以通过判断timerexpired值来退出程序。另外,全局变量force表示我们是否在发出请求后需要等待服务器的响应结果。

四、昨天,今天,明天

了解了webbench的具体代码以后,下面一步就要考虑一下如何进行改进了。代码中有一些过时的函数可以更新一下,加入一些新的功能,例如支持POST方法,支持异步压测等,这些就留到以后去探索了。第一次写源码分析,望多多指教。希望本文能帮助大家在以后与webbench愉快地玩耍。且用且珍惜!

压力测试webbench(转)的更多相关文章

  1. Nginx配置性能优化与压力测试webbench【转】

    这一篇我们来说Nginx配置性能优化与压力测试webbench. 基本的 (优化过的)配置 我们将修改的唯一文件是nginx.conf,其中包含Nginx不同模块的所有设置.你应该能够在服务器的/et ...

  2. nginx压力测试webbench

    下载压力测试工具webbench wget http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.gz 安装依赖包 yum -y in ...

  3. 压力测试 webbench

    Linux下 webbench最多可以模拟3万个并发连接去测试网站的负载能力 webbench -c -t http://127.0.0.1/phpinfo.php 说明: -c 客户端数量(并发数量 ...

  4. Linux下四款Web服务器压力测试工具(http_load、webbench、ab、siege)介绍

    一.http_load程序非常小,解压后也不到100Khttp_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把 ...

  5. 网站压力测试工具webbench使用说明

    一.webbench简介        Webbench是有名的网站压力测试工具,它是由Lionbridge公司(http://www.lionbridge.com)开发.它的帮助文件和文档请到:ww ...

  6. webbench 压力测试

    原文 webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好用,安装使用也特别方便,并且非常小. 主要是 -t 参数用着比较爽,下面参考了张宴 ...

  7. 找到一款不错的网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装: 引用 wget htt ...

  8. Nginx使用webbench进行压力测试

    在运维工作中,压力测试是一项非常重要的工作.比如在一个网站上线之前,能承受多大访问量.在大访问量情况下性能怎样,这些数据指标好坏将会直接影响用户体验. 但是,在压力测试中存在一个共性,那就是压力测试的 ...

  9. Webbench网站压力测试

      Webbench是有名的网站压力测试工具,能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况.webBech的标准测试可以向我们展示服务器的 两项 内容:每秒钟相应请求数和每秒 ...

随机推荐

  1. Vue 在beaforeCreate时获取data中的数据

    众所周知,vue在beforecreate时期是获取不到data中的 数据的 但是通过一些方法可以实现在beforecreate时获取到data中的数据 暂时想到两种放发可以实现,vue在before ...

  2. 通过JS加载XML文件,跨浏览器兼容

    引言 通过JS加载XML文件,跨多种浏览器兼容. 在Chrome中,没有load方法,需要特殊处理! 解决方案 部分代码 try //Internet Explorer { xmlDoc=new Ac ...

  3. resnet.caffemodel

    http://blog.csdn.net/baidu_24281959/article/details/53203757

  4. day02五大运算符:逻辑运算符、成员运算符、算数、比较、赋值、

    # -*- encoding: utf-8 -*-# print('hello 中国')# 变量# print(10 + 20 + 3 + 15)# print((10 + 20 + 3 + 15)* ...

  5. [IOS初学]ios 第一篇 storyboard 与viewcontroller的关系 - Zoe_J

    时间 2014-07-27 16:08:00  博客园-所有随笔区 原文  http://www.cnblogs.com/zoe-j/p/3871501.html 主题 StoryBoard 学习了一 ...

  6. VW结合rem进行移动端布局

    ---恢复内容开始--- html { font-size:10vw: } div { width: 1rem; height: 1rem; } VW这个单位适合用来适应不同设备的 一个设备的宽度就为 ...

  7. (7) 将tomcat HTTP连接器启动在80端口(jsvc使用详解)

    让tomcat在80端口上运行 法一: 修改连接器的端口8080为80 <Connector port="8080" protocol="HTTP/1.1" ...

  8. db2快速删除大表数据(亲测可用)

    一.推荐.删了不可恢复 TRUNCATE TABLE table_name IMMEDIATE 二. DB2 LOAD FROM d:\DB2_BAK\null.del of del REPLACE ...

  9. Python爬虫-Scrapy-CrawlSpider与ItemLoader

    一.CrawlSpider 根据官方文档可以了解到, 虽然对于特定的网页来说不一定是最好的选择, 但是 CrwalSpider 是爬取规整的网页时最常用的 spider, 而且有很好的可塑性. 除了继 ...

  10. 《算法导论》— Chapter 15 动态规划

    序 算法导论一书的第四部分-高级设计和分析技术从本章开始讨论,主要分析高效算法的三种重要技术:动态规划.贪心算法以及平摊分析三种. 首先,本章讨论动态规划,它是通过组合子问题的解而解决整个问题的,通常 ...