apache 用Flood进行WEB服务器测试
时间:2006-04-09 来源:softiger
Checking out flood
The current copy of flood is available via Subversion. Flood also depends on the apr and apr-util packages available from the same Subversion repository. Note: Flood will automatically detect and configure APR and APR-util if they are in the appropriate subdirectories. If you have an already installed copy of APR and APR-util (such as the ones that come with httpd-2.0 or Subversion), you may specify --with-apr and --with-apr-util at configure-time. % svn co http://svn.apache.org/repos/asf/httpd/test/trunk/flood
% cd flood
% svn co http://svn.apache.org/repos/asf/apr/apr/trunk apr
% svn co http://svn.apache.org/repos/asf/apr/apr-util/trunk apr-util
Configuring flood and its dependencies
Now that you have all of the required modules checked out, you now need to generate the configure scripts and execute them for your platform. Flood and SSL support
Note: SSL support is not enabled by default in flood. If you wish to enable SSL support, you must specify --enable-ssl when configuring flood. If you attempt to run flood against a https URL without SSL support compiled-in, you will receive an error similar to the following: % ./flood examples/round-robin-ssl.xml
open request failed (https://www.modssl.org/example/test.phtml).
Error running farmer 'Joe': This function has not been implemented on this
platform
The --enable-ssl option enables detection of the OpenSSL libraries. If flood can not automatically detect OpenSSL, you will need to specify --with-openssl to point at the appropriate installed version of OpenSSL. The --with-capath option points at a directory that contains the Certificate Authorities (CAs) for OpenSSL. The default capath is in $openssl_prefix/certs. Running configure from the flood directory
% ./buildconf
% ./configure --disable-shared
Compiling flood and its dependencies
In this example, APR and apr-util will automatically be built with flood. So, you only need to issue a make in the flood directory. % make all
Running flood
By default, flood is a static executable, so the executable is relocatable. There are some example flood profiles in the examples/ directory from CVS. % ./flood examples/round-robin.xml > foo.out
Analyzing flood output
The foo.out file generated above is in a simple easy-to-parse format. There are some included shell and awk scripts in the examples directory that provide some easy mechanisms to extract info from the flood output files. % ./examples/analyze-relative foo.out
Questions
This should provide a quick and easy way to jumpstart your flood installation. If you have any questions, please email the [email protected] mailing list.
====================================================================
<?xml version="1.0" standalone="no"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<flood configversion="1">
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description> <!-- Replace with your own domain (see RFC 2606, Section 3) -->
<baseurl>http://www.example.com</baseurl> <!-- Simple multipart/form-data POST. Contains one plain variable 'foo' with
value 'bar' and file variable 'logo', which refers to file 'asf_logo.gif'.
Plese note, that this example has string 'XML encoded binary file
contents' as file body, instead of actual data. This is intended, to make
this example simple. In real scenario this string would have to be
replaced by file contents encoded as XML entities. -->
<url method="POST"
Content-Type="multipart/form-data; boundary=AaB03x"
payload="--AaB03x
Content-Disposition: form-data; name="foo"

bar
--AaB03x
Content-Disposition: form-data; name="logo"; filename="asf_logo.gif"
Content-Type: image/gif

XML encoded binary file contents;
--AaB03x--">/foo</url> <!-- Example XML-RCP query, as found in protocol spec. It calls method
'examples.getStateName' with one integer argument. -->
<url method="POST"
Content-Type="text/xml"
payload="<xml version="1.0"><methodCall><methodName>examples.getStateName</methodName><params><param><value><i4>41</i4></value></param></params></methodCall>">/foo</url>
</urllist> <profile>
<name>RoundRobinProfile</name>
<description>Round Robin Configuration</description>
<useurllist>Test Hosts</useurllist>
<profiletype>round_robin</profiletype>
<socket>generic</socket>
<verify_resp>verify_200</verify_resp>
<report>relative_times</report>
</profile> <farmer>
<name>Joe</name>
<useprofile>RoundRobinProfile</useprofile>
</farmer> <farm>
<name>Bingo</name>
<usefarmer>Joe</usefarmer>
</farm> </flood>
========================================================
<?xml version="1.0" standalone="no"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<!-- Hi, I'm a flood config file. -->
<flood configversion="1">
<!-- A urllist describes which hosts and which methods we want to hit. -->
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<!-- Find FAQ on HTTPD project page -->
<url method="GET" responsetemplate="<a href="([^"]*)">FAQ</a>" responsename="faq">http://httpd.apache.org/</url>
<url method="GET" requestparamcount="1" requesttemplate="http://httpd.apache.org${faq}" />
<!-- Search for httpd-2.0 commit access.
<url method="POST" payload="method=and&format=builtin-long&sort=score&config=htdig&restrict=&exclude=&words=httpd-2.0+commit+access" responsetemplate="<a href="([^"]*)">" responsename="id">http://www.apachelabs.org/cgi-bin/htsearch</url>
<url method="GET" requesttemplate="${id}" responsetemplate="Prev</A> <A HREF="([^"]*)">" responsename="next" />
<url method="GET" requestparamcount="1" requesttemplate="http://www.apachelabs.org${next}" />
-->
<!-- Search google.com for "foo" and go to the first search result.
<url method="GET" responsetemplate="<a href=http://([^>]*)>" responsename="foo">http://www.google.com/search?q=foo</url>
<url method="GET" requestparamcount="1" requesttemplate="http://${foo}" />
-->
</urllist> <!-- The profile describes how we will hit the urllists.
Round robin runs all of the URLs in the urllist in order once. -->
<profile>
<name>RoundRobinProfile</name>
<description>Round Robin Configuration</description> <useurllist>Test Hosts</useurllist> <!-- Profile Events -->
<profiletype>round_robin</profiletype>
<!--socket>generic</socket-->
<socket>keepalive</socket> <!-- Verification Events -->
<verify_resp>verify_200</verify_resp> <!-- Reporting Events -->
<report>easy</report>
</profile> <!-- A farmer runs one profile a certain number of times. -->
<farmer>
<name>Joe</name>
<!-- run the Joe farmer 5 times -->
<count>5</count>
<!-- Joe uses this profile -->
<useprofile>RoundRobinProfile</useprofile>
</farmer> <!-- A farm contains a bunch of farmers - each farmer is a thread. -->
<farm>
<name>Bingo</name>
<usefarmer count="1">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests -->
<seed>23</seed>
</flood>
========================================================
<?xml version="1.0"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<!-- Hi, I'm a flood config file. They call me "round-robin.xml"
I am an example of a "round-robin" configuration. All of the URLs in
the urllist "Test Hosts" will be hit in sequential order.
Flood's syntax is XML based.
After compiling flood (./configure && make), you can execute me as:
./flood examples/round-robin.xml
(The path to me.) Flood will then output data to stdout in the format as specified below
(relative_times) for each URL that it hits:
998951597871780 1389 57420 7960273 7960282 OK 4 http://www.apache.org/
The columns are as follows:
- Absolute Time in usec that the request was started by flood
- Relative Time in usec (to first column) that it took to open the socket
to the specified server
- Relative Time in usec (to first column) that it took to write the
generated request to the server.
- Relative Time in usec (to first column) that it took to read the
generated response from the server.
- Relative Time in usec (to first column) that it took to close the
socket. On a keepalive socket, it may not close the socket.
- OK/FAIL indicates what the verification module (in this case,
verify_200) thought of the request.
- The thread/process id of the farmer that made the request.
- The URL that was hit (without query strings) To get a "nice" summary of the output (as well as an idea of how to
further process this info), try out:
./flood examples/round-robin.xml > my-output
./examples/analyze-relative my-output
-->
<flood configversion="1">
<!-- A urllist describes which hosts and which methods we want to hit. -->
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<!-- We first send a POST request to search.apache.org looking for "foo"
Notice the payload attribute - this allows us to specify the POST
content. -->
<url method="POST" payload="version=2&keyword=foo&results=20&what=apr.apache.org">http://search.apache.org/index.cgi</url>
<!-- Then, we perform a HEAD request on www.apache.org -->
<url method="HEAD">http://www.apache.org/</url>
<!-- Then, we retrieve the index page of dev.apache.org -->
<url method="GET">http://dev.apache.org/</url>
<!-- The default method is "GET", so let's get APR's index page. -->
<url>http://apr.apache.org/</url>
</urllist> <!-- The profile describes how we will hit the urllists. For this
example, we execute with the round_robin profile.
Round robin runs all of the URLs in the urllist in order once. -->
<profile>
<name>Example Profile</name>
<description>A Test Round Robin Configuration</description> <!-- See above. This indicates which URLs we will hit. -->
<useurllist>Test Hosts</useurllist> <!-- Specifies that we will use round_robin profile logic -->
<profiletype>round_robin</profiletype>
<!-- Specifies that we will use generic socket logic
We also have "keepalive" as an option - this option indicates that
we should attempt to use HTTP Keepalive when available. -->
<socket>generic</socket>
<!-- Specifies that we will use verify_200 for response verification
This verification step ensures that we received a 2xx or 3xx
status code from the server. -->
<verify_resp>verify_200</verify_resp>
<!-- Specifies that we will use the "relative_times" report generation
We also have "easy" - this option is similar to "relative_times",
but the times posted are absolute instead of relative to the start
of the request. -->
<report>relative_times</report> </profile> <!-- A farmer runs one profile a certain number of times. This farmer is
called Joe. -->
<farmer>
<name>Joe</name>
<!-- We run the Joe farmer 5 times
Note that we have the "time" option which indicates for how many
seconds a farmer should run. The "time" and "count" elements are
exclusive. -->
<count>5</count>
<!-- Farmer Joe uses this profile -->
<useprofile>Example Profile</useprofile>
</farmer> <!-- A farm contains a bunch of farmers - each farmer is an independent
worker (i.e. a thread or child process). -->
<farm>
<!-- We call our farm "Bingo" - note that the farm must be called Bingo
in the current implementation. -->
<name>Bingo</name>
<!-- We will start 5 farmers named Joe. We will start 2 farmers every 5
seconds. -->
<usefarmer count="5" startcount="2" startdelay="5">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests.
Flood uses a seeded PRNG - this allows the tests which use random
numbers to be reproduced. -->
<seed>1</seed>
</flood>
<!-- That's all folks! -->
========================================================
<?xml version="1.0" standalone="no"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<!-- Hi, I'm a flood config file. -->
<flood configversion="1">
<!-- A urllist describes which hosts and which methods we want to hit. -->
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<url method="POST" payload="version=2&keyword=foo&results=20&what=apr.apache.org" predelay="1" predelayprecision="5">http://search.apache.org/index.cgi</url>
<url method="HEAD" postdelay="2" postdelayprecision="2">http://www.apache.org/</url>
<url method="GET" predelay="1" postdelay="1">http://dev.apache.org/</url>
<url method="POST" payload="version=2&keyword=foo&results=20&what=apr.apache.org">http://search.apache.org/index.cgi</url>
<url method="POST" payloadparam="random" payloadparamcount="1" payloadtemplate="version=2&keyword=foo$$&results=20&what=apr.apache.org">http://search.apache.org/index.cgi</url>
<url method="HEAD">http://www.apache.org/</url>
<url method="GET">http://dev.apache.org/</url>
<url>http://apr.apache.org/</url>
</urllist> <!-- The profile describes how we will hit the urllists.
Round robin runs all of the URLs in the urllist in order once. -->
<profile>
<name>RoundRobinProfile</name>
<description>Round Robin Configuration</description> <useurllist>Test Hosts</useurllist> <!-- Profile Events -->
<profile_init>round_robin_profile_init</profile_init>
<get_next_url>round_robin_get_next_url</get_next_url>
<create_req>round_robin_create_req</create_req>
<loop_condition>round_robin_loop_condition</loop_condition>
<profile_destroy>round_robin_profile_destroy</profile_destroy> <!-- Socket Events -->
<!-- default socket_init -->
<!-- default begin_conn -->
<!-- default send_req -->
<!-- default recv_resp -->
<!-- default end_conn -->
<!-- default socket_destroy --> <!-- Verification Events -->
<verify_resp>verify_200</verify_resp> <!-- Reporting Events -->
<report_init>simple_report_init</report_init>
<process_stats>simple_process_stats</process_stats>
<report_stats>simple_report_stats</report_stats>
<destroy_report>simple_destroy_report</destroy_report>
</profile> <!-- A farmer runs one profile a certain number of times. -->
<farmer>
<name>Joe</name>
<!-- run the Joe farmer 5 times -->
<count>5</count>
<!-- Joe uses this profile -->
<useprofile>RoundRobinProfile</useprofile>
</farmer> <!-- A farm contains a bunch of farmers - each farmer is a thread. -->
<farm>
<name>Bingo</name>
<usefarmer count="1">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests -->
<seed>23</seed>
</flood>
========================================================
<?xml version="1.0"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<!-- Hi, I'm a flood config file.
This is a keepalive-enabled profile. -->
<flood configversion="1">
<!-- A urllist describes which hosts and which methods we want to hit. -->
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<!-- change element below to point to default Apache 2.0 installation -->
<baseurl>http://localhost</baseurl>
<url>/index.html.en</url>
<url>/manual/index.html.en</url>
<url>/manual/mod/index.html.en</url>
</urllist> <!-- The profile describes how we will hit the urllists.
Round robin runs all of the URLs in the urllist in order once. -->
<profile>
<name>RoundRobinProfile</name>
<description>Round Robin Configuration</description> <useurllist>Test Hosts</useurllist> <!-- Profile Events -->
<profile_init>round_robin_profile_init</profile_init>
<create_req>round_robin_create_req</create_req>
<get_next_url>round_robin_get_next_url</get_next_url>
<loop_condition>round_robin_loop_condition</loop_condition>
<profile_destroy>round_robin_profile_destroy</profile_destroy> <!-- Socket Events -->
<socket_init>keepalive_socket_init</socket_init>
<begin_conn>keepalive_begin_conn</begin_conn>
<send_req>keepalive_send_req</send_req>
<recv_resp>keepalive_recv_resp</recv_resp>
<end_conn>keepalive_end_conn</end_conn>
<socket_destroy>keepalive_socket_destroy</socket_destroy> <!-- Verification Events -->
<verify_resp>verify_200</verify_resp> <!-- Reporting Events -->
<report_init>easy_report_init</report_init>
<process_stats>easy_process_stats</process_stats>
<report_stats>easy_report_stats</report_stats>
<destroy_report>easy_destroy_report</destroy_report>
</profile> <!-- A farmer runs one profile a certain number of times. -->
<farmer>
<name>Joe</name>
<!-- run the Joe farmer 1000 times -->
<count>1000</count>
<!-- Joe uses this profile -->
<useprofile>RoundRobinProfile</useprofile>
</farmer> <!-- A farm contains a bunch of farmers - each farmer is a thread. -->
<farm>
<name>Bingo</name>
<!-- Create 10 identical Joe farmers executing in parallel. -->
<usefarmer count="10">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests -->
<seed>23</seed>
</flood>
========================================================
<?xml version="1.0"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<!-- Hi, I'm a flood config file. -->
<flood configversion="1">
<!-- A urllist describes which hosts and which methods we want to hit. -->
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<url method="POST" payload="version=2&keyword=foo&results=20&what=apr.apache.org">http://search.apache.org/index.cgi</url>
<url method="HEAD">http://www.apache.org/</url>
<url method="GET">http://dev.apache.org/</url>
<url>http://apr.apache.org/</url>
</urllist> <!-- The profile describes how we will hit the urllists.
Round robin runs all of the URLs in the urllist in order once. -->
<profile>
<name>RoundRobinProfile</name>
<description>Round Robin Configuration</description> <useurllist>Test Hosts</useurllist> <!-- Specifies that we will use round_robin profile logic -->
<profiletype>round_robin</profiletype>
<!-- Specifies that we will use generic socket logic -->
<socket>generic</socket>
<!-- Specifies that we will use verify_200 for response verification -->
<verify_resp>verify_200</verify_resp>
<!-- Specifies that we will use the "easy" report generation -->
<report>relative_times</report> </profile> <!-- A farmer runs one profile a certain number of times. -->
<farmer>
<name>Joe</name>
<!-- run the Joe farmer 5 times -->
<count>5</count>
<!-- Joe uses this profile -->
<useprofile>RoundRobinProfile</useprofile>
</farmer> <!-- A farm contains a bunch of farmers - each farmer is a thread. -->
<farm>
<name>Bingo</name>
<usefarmer count="1">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests -->
<seed>23</seed>
</flood>
========================================================
<?xml version="1.0"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<flood configversion="1">
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<url>https://www.modssl.org/example/test.phtml</url>
<!-- This site is currently down
<url>https://mozilla-crypto.ssleay.org/cryptocheck.php</url>
-->
</urllist> <profile>
<name>RoundRobinProfile</name>
<description>Test of the Round Robin Configuration</description> <useurllist>Test Hosts</useurllist> <!-- Profile Events -->
<profiletype>round_robin</profiletype> <!--socket>generic</socket-->
<socket>keepalive</socket> <!-- Verification Events -->
<verify_resp>verify_200</verify_resp> <!-- Reporting Events -->
<report>simple</report>
</profile> <farmer>
<name>Joe</name>
<!-- run the Joe farmer 2 times -->
<count>2</count>
<!-- Joe uses this profile -->
<useprofile>RoundRobinProfile</useprofile>
</farmer> <farm>
<name>Bingo</name>
<usefarmer count="1">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests -->
<seed>23</seed>
</flood>
========================================================
<?xml version="1.0"?>
<!DOCTYPE flood SYSTEM "flood.dtd">
<!-- Hi, I'm a flood config file. -->
<flood configversion="1">
<!-- A urllist describes which hosts and which methods we want to hit. -->
<urllist>
<name>Test Hosts</name>
<description>A bunch of hosts we want to hit</description>
<url method="POST" payload="version=2&keyword=foo&results=20&what=apr.apache.org">http://search.apache.org/index.cgi</url>
<url method="HEAD">http://www.apache.org/</url>
<url method="GET">http://dev.apache.org/</url>
<url>http://apr.apache.org/</url>
</urllist> <!-- The profile describes how we will hit the urllists.
Round robin runs all of the URLs in the urllist in order once. -->
<profile>
<name>RoundRobinProfile</name>
<description>Round Robin Configuration</description> <useurllist>Test Hosts</useurllist> <!-- Specifies that we will use round_robin profile logic -->
<profiletype>round_robin</profiletype>
<!-- Specifies that we will use generic socket logic -->
<socket>generic</socket>
<!-- Specifies that we will use verify_200 for response verification -->
<verify_resp>verify_200</verify_resp>
<!-- Specifies that we will use the "easy" report generation -->
<report>easy</report> </profile> <!-- A farmer runs one profile a certain number of times. -->
<farmer>
<name>Joe</name>
<!-- run the Joe farmer for 30 seconds -->
<time>30</time>
<!-- Joe uses this profile -->
<useprofile>RoundRobinProfile</useprofile>
</farmer> <!-- A farm contains a bunch of farmers - each farmer is a thread. -->
<farm>
<name>Bingo</name>
<usefarmer count="1">Joe</usefarmer>
</farm> <!-- Set the seed to a known value so we can reproduce the same tests -->
<seed>23</seed>
</flood>
========================================================
当你设置好服务器投入使用后,你最关心的事莫过于服务器的性能了。你可以用一些手动的方法进行测试,但手动方法有很多局限性。
先不论手工测试方法所投入的时间和精力问题,用手工方法测试的一大不足就是它不容易揭示出你的站点的真正问题所在,是服务器设置的问题还是因为一些动态组件又或是网络基础设施造成的问题?
幸运的Apache HTTP工程包含了一个名为HTTPD-Test的子工程,正如这个名称所揭示的,这是一个Apache的通用测试工具包,这个包里包含了大量的不同工具,而本文将主要介绍其中一个名为洪水(Flood)的工具,它之所以如此命名,是因为它利用向服务器发出洪水般的大量请求测试服务器的响应时间。
当你设置好服务器投入使用后,你最关心的事莫过于服务器的性能了。你可以用一些手动的方法进行测试,但手动方法有很多局限性。
先不论手工测试方法所投入的时间和精力问题,用手工方法测试的一大不足就是它不容易揭示出你的站点的真正问题所在,是服务器设置的问题还是因为一些动态组件又或是网络基础设施造成的问题?
幸运的Apache HTTP工程包含了一个名为HTTPD-Test的子工程,正如这个名称所揭示的,这是一个Apache的通用测试工具包,这个包里包含了大量的不同工具,而本文将主要介绍其中一个名为洪水(Flood)的工具,它之所以如此命名,是因为它利用向服务器发出洪水般的大量请求测试服务器的响应时间。
洪水使用一个XML文件来进行必要的测试设置,包括测试中使用的URL和POST数据和准备测试的服务器组,然后Flood开始测量以下一系统操作的时间:
●打开一个到服务器的socket
●向socket写入对服务器的请求
●读出服务器的响应
●关闭socket
当测试结束,管理员就可以了解到是否存在Apache服务器(或其它HTTP服务器)的设置问题,服务器的实际负荷,硬件的性能表现和是否存在着网络基础设置瓶颈。
安装Flood
你可以在Apache网站下载httpd-test和apr/apr-util软件包,后者是当从Apache的CVS服务器上直接build时所需要的。你必需先进行登录(密码是"anoncvs")
$ cvs -d :pserver:[email protected]:/home/cvspublic login
$ cvs -d :pserver:[email protected]:/home/cvspublic co httpd-test/flood
$ cd httpd-test/flood
$ cvs -d :pserver:[email protected]:/home/cvspublic co apr
$ cvs -d :pserver:[email protected]:/home/cvspublic co apr-util
如果你取得了源码,你可以用下面的命令安装:
$ buildconf
$ configure
$ make all
现在,安装完成了。
设置Flood
Flood通过一个XML格式的设置文件来定义测试中使用的各种参数,我们不妨通过一个形象的比喻也说明一下Flood的工作过程和需要设置的各个方面。首先,Flood使用一个模型(profile)来定义一组给定的URL如何被访问,具体的访问由一个或多个农夫(farmer)来进行,而这些农夫又属于一个或多个农场(farm),我们来看一下下面这个示意图:
如图所示,现在我们使用一个农场,这个农场有两组农夫,其中农夫组Joe使用访问模型A与一个包含五个地址的URL列表,农夫组B使用访问模型B与一个包含三个URL的地址列表,这些家夫直接向WEB服务器请求列表中的地址。Flood使用线程来创建各个农夫,然后比较各个农夫收集到的数据并存入一个单独的文件以便之后做进一步的处理。
XML文件包括了这个测试需要定义的四个方面:URL列表,访问模型,农夫和农场。
URL列表也即一组即将被访问的地址的列表,这些URL地址可以被简单的引用进一步定义特定的请求方法(GET,POST,HEAD)。
访问模型定义测试使用哪一个地址列表,它们如何被访问,使用哪一种Socket,收集的信息如何被报告。
农夫负责实际的请求过程,对农夫唯一的可设置选项是使用哪一个访问模型和对一个访问模型的调用次数。每个农夫独立的执行自己的访问模型,但一个访问模型可以执行多次,因此最后的请求过程可能是这样:地址一、地址二、地址一、地址二、……。
对家场的定义涉及到创建农夫的数目和时间,通过增加一个家场创建农夫的数目,可以增加并发请求的数目。并通一些附加的设置,你可以设置一些初始数目的农夫,然后每隔特定的时间增加一定的农夫数量。例如,你可以开始创建两个农夫,然后每5秒钟增加一个农夫,直到农夫数目达到20时停止增加。这可以在一个给定的期间形成一个最大20的并发访问升级过程,然后又逐步将并发请求数降到0。另外也可以模拟这种访问情况,一定数目的访问者长时期的访问一系列页面,并操持最大并发请求数在5-6之间。
注意:到写这篇文章的时候为止,目前的Flood仅支持一个农场,而且它的名子必须是"Bingo",不过,通过为一个农场定义多个农夫,你可以取得同样的基本效果。
通过调节农夫,农场和URL列表的参数,你可以控制总请求数,并发请求数,测试时间(基于URL列表,重复次数和农夫的数量可以决定这一点),以及这些请求在整个测试期间的分布,这就允许你针对不同的条件订制你的测试。
在使用Flood进行测试设置时你应该记住的三个基本点是:
●地址列表定义了农夫们将访问的地址
●每个农夫的重复数目定义了一个用户访问你的站点的次数。
●一个农场的农夫数目定义了并发访问用户的数目。
在Flood发行包里的examples目录下有一个样例设置文件,round-robin.xml可能是一个最适合初学者学习的例子,不过本文并不准备就编辑此XML文件的规则或处理产生的数据文件做进一步的解说。
这里,我们主要想讲一下如何针对不同类型的WEB服务器来调整测试的参数。为了便于理解后面的内容,这里我们先看一下使用examples目录下的analyze-relative测试脚本得到的一个结果。在这个例子中,测试对象是一台内部服务器。
Slowest pages on average (worst 5):
Average times (sec)
connect write read close hits URL
0.0022 0.0034 0.0268 0.0280 100 http://test.mcslp.pri/java.html
0.0020 0.0028 0.0183 0.0190 700 http://www.mcslp.pri/
0.0019 0.0033 0.0109 0.0120 100 http://test.mcslp.pri/random.html
0.0022 0.0031 0.0089 0.0107 100 http://test.mcslp.pri/testr.html
0.0019 0.0029 0.0087 0.0096 100 http://test.mcslp.pri/index.html
Requests: 1200 Time: 0.14 Req/Sec: 9454.08
在这里你可以看到测试中进行连接(connect),请求(write/request),回应(read /response),关闭连接(close)的平均时间。你也可以对服务器每称处理的请求数目有个基本的印象。
对于新闻类站点的测试
对于如New York Times、Slashdot之类的新闻站点以及一些BLOG之类,它们都有一个主要的首页,首页上有着众多到栏目页和内容页的连接,对某条信息感兴趣的读者可以点进去仔细阅读。
通常情况下,这类站点的首页访问量相对固定而对于其它页面,访问量的变化就会更大一些。如果它推出了RSS/RDF订阅服务,那么就会出现一定量的直接到内容页的流量而不经过首页。大部分的此类站点都使用了某种内容的动态化技术,而Flood是测试这类动态站点的一个不错方法,特别你可以将之与一些静态站的响应相对比。
你可以用以下的参数设置模拟对一个新闻类型的网站的访问:
|
Farmer Set A |
Farmer Set B |
Farmer Set C |
URL List |
Homepage Only |
Homepage +3 stories |
3 story pages |
Repeat Count |
1 |
3 |
3 |
Count |
100 |
20 |
20 |
Start Count |
5 |
5 |
5 |
Start Delay |
1 |
5 |
5 |
Notes |
Home page only |
Homepage+Stories |
Stories only (RSS) |
测试在线商店站点
在线商店,在线商品目录或其它一些更具交互性的网站则有不同的使用模型。虽然仍会有一部分人到达你的首页,一些人会直接进入你站内的某一个页面,大多数用户会在你的站里找来找去,他们可能会在一个产品页上浏览大量的产品,进行一些搜索或者点击进入一些相关的产品页面。
因此,你应该用更大数量的地址列表测试这类站点,更大的重复次数(以模拟大量的用户)和相对新闻类站点比较低的并发访问数目:
|
Farmer Set |
URL List |
10-15 pages |
Repeat Count |
5 |
Count |
50 |
Start Count |
5 |
Start Delay |
5 |
测试 "Slashdot" 效应
有时,你必须测试你的系统能否应付某个特定时刻大量用户同时访问你的网站的情况。很多网站已经遇到过这个问题,一次重大事件中对于Slashdot网站的几个页面的引用就引发了对这个页面的巨量并发请求。
典型的情况下这些请求仅针对一个特殊的页面,我们可以通过在Flood中创建成百上千的家夫来并发请求服务器上的特定页面来模拟这种情况,通过设置高重复率和延迟系统来模拟一定时间内大量用户的连续访问。
|
Farmer Set |
URL List |
1 page |
Repeat Count |
50 |
Count |
250 |
Start Count |
100 |
Start Delay |
1 |
测试技巧
为了让以上各类测试都工作得很好,你应该记住以下几点:
●最重要的是,不要直接在WEB服务器上用Flood进行测试,如果你这样做你仅仅是在测试一台机器打开一个网络连接与自己通讯的能力,一定要在另一台机器上进行测试。●要对自己机器的一些技术限制有所了解,这包括你机器容许的最大线程数和最大网络连接数,如果你试图创建超过这个限制的农夫将会带来让人难以理解的测试结果。
●Flood是一个客户端解决方案,因此对于在多台机器上进行测试没有任何限制。事实上我们推荐你这样做,因为这是一个在想进行饱和性测试时避免你的客户机系统的技术限制的好方法。
●Flood测试由于是在客户机上运行,它的表现也要依赖于客户的性能,如果客户机系统处于繁忙的状态,Flood进程会与其它客户进程一样被阻塞,因此,最好使用一台专用的客户机进行测试,如果客户机上还运行着其它任务,在开始测试之前最好关掉它们。