I’ve been doing some experiments recently with WCF, seeing how much load I can throw at different configurations. I’m especially interested in seeing what difference async web services can make with IO intensive operations. One problem I had was finding a good HTTP load tool. I tried to get WCAT working, but found it complex and hard to understand. It also gives almost no feedback at all when you get something wrong.
In the end I wrote my own little load tool around WebRequest. It’s almost trivial, but there are few little hoops you need to jump through in order to make it work. I’ve wrapped it up as a little console application, WebStresser. You can get the source from github here:
Or download a precompiled binary which requires .NET 3.5 or greater to work. It’s also reported to work fine on Mono:
To use it, just run it with a minimum of a URL:
Starting test... Completed: 0 Faulted: 0 Connections: 1 Completed All 1 Faulted 0 Elapsed ms 2,001 Calls per second 0 Avergate call duration ms 1,127
By default it just executes a single GET request to the given URI. If you want to see the response, add the –r option:
webstresser -u=http://localhost:5401/ -r
Starting test... Completed: 0 Faulted: 0 Connections: 1 http://localhost:5401/ Status: 200, OK X-AspNetMvc-Version: 3.0 Connection: Close Content-Length: 7259 Cache-Control: private Content-Type: text/html; charset=utf-8 Date: Wed, 02 Mar 2011 21:49:37 GMT Server: ASP.NET Development Server/10.0.0.0 X-AspNet-Version: 4.0.30319 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3. .... etc
To run a load test, just tell it how many requests to make with the –i option, and the delay, in milliseconds, between each request with the –t option. Here I’m running 100 requests 20 ms apart:
webstresser -u=http://localhost:5401/ -i=100 -t=20
Finally here’s an example calling a SOAP web service. Note the SOAPAction header and the –p option that points to a file with the postdata:
webstresser -u=http://mike-2008r2:8123/proxy -m=POST -i=100 -t=10 -p=postdata.txt -H=SOAPAction:http://tempuri.org/ICustomerService/GetCustomerDetails
webstresser -h Options -?, -h, --help -u, --uri=VALUE REQUIRED: The URI you want to call -m, --method=VALUE The HTTP method. Default is GET -i, --iterations=VALUE Number of iterations to run, default is 1 -t, --interval=VALUE Iterval between each call in milliseconds, default is 10000 -p, --postdata=VALUE Path to file containing post data -r, --responses Print responses -k, --keepalive KeepAlive header value (true or false), default is true -a, --accept=VALUE Accept header value, default is 'text/xml' -c, --contenttype=VALUE ContentType header value, default is 'text/xml; charset="utf-8"' -z, --timeout=VALUE Timeout in milliseconds, default is 10000 -H[=VALUE1:VALUE2] Add a header to the request. e.g: -H MyHeader= MyValue
I’m using the excellent Mono.Options library to do command line processing. It makes putting this kind of tool together very easy.