Stress testing WordPress on a single node VPS

Lately I’ve been trying to find a cheap close-to-perfect-but-not-so-difficult-to-setup solution for my personal blog. A kind of “set and forget” thing if you will.
Until now, my blog was running on a Dell Dual-Xeon /w 2GB RAM cPanel server (along with a few other sites) and was working pretty smooth. Based on pingdom’s full page test my blog needed 6-7 seconds to fully load which is kind of acceptable considering the theme, the twitter/flickr integration on the sidebar and the needed dns queries to contact facebook, google analytics and woopra servers.

Last night bestvpscloud from the VPS.NET forums pointed out to this script that installs nginx, php5, mysql, exim4 and wordpress on low-end VPS servers, and after reading the comments I got to this guy’s blog who also suggested adding the dotdeb.org repository and upgrade to PHP 5.3.

Initial setup

So I setup a single node VPS.NET server on the new SAN 2.0 cloud in London and started playing around with the stock Debian 5.0 x64 template. To be honest, 21andy’s script didn’t work for me, it somehow messed things up and I had to re-install the VPS from scratch. What I did was first complete the process the way LowEndAdmin suggested, and then modify sources.list and upgrade mysql, php and nginx.

The commands

Here’s a quick step by step guide of what I did:

1. After deploying the template image to my VPS, I logged in using root, downloaded LowEndBox’s script

wget http://github.com/lowendbox/lowendscript/raw/master/setup-debian.sh

and ran the following commands:

bash setup-debian.sh system
bash setup-debian.sh exim4
bash setup-debian.sh nginx
bash setup-debian.sh mysql
bash setup-debian.sh php
bash setup-debian.sh wordpress georgetasioulis.com

2. Then I wanted to upgrade PHP to 5.3 and mysql to their latest (via apt-get available) packages.

nano /etc/apt/sources.list

and added

deb http://packages.dotdeb.org stable all
deb-src http://packages.dotdeb.org stable all
deb http://php53.dotdeb.org stable all
deb-src http://php53.dotdeb.org stable all

and finally ran

gpg --keyserver keys.gnupg.net --recv-key 89DF5277
gpg -a --export 89DF5277 | apt-key add -

apt-get update && apt-get upgrade

3. Last step was to upgrade nginx from the sid repository which was pretty straightforward.

invoke-rc.d nginx stop

cat >> /etc/apt/sources.list <<END
deb http://ftp.us.debian.org/debian sid main
END

apt-get update
apt-get -y install nginx

4. Post-install actions were
a. to remove the sid repository

cat >> /etc/apt/sources.list <<END
#deb http://ftp.us.debian.org/debian sid main
END

b. to restart the updated daemons

invoke-rc.d nginx restart
invoke-rc.d php-cgi restart
invoke-rc.d mysql restart

c. do a final apt-get upgrade

apt-get update
apt-get -y upgrade

d. and finally reboot the server

reboot

First results

My (empty) WordPress blog was now up and running, so all I had to do now was move the files and database dump from the one server to the other. A few minutes later my blog was up and running and all I had to do was to change my domain’s DNS settings to reflect the new server’s IP and wait for it to propagate.

OK so now you’ll be asking yourselves “so what, big deal”. Except that:

  • My load times dropped from 6-7 seconds to 2-3 seconds.
  • I had no problem running a complete loadimpact.com free test (no latency increase, max load was 0.60)
  • I successfully installed XCache and the W3 Total Cache plugin which made load times even faster and cpu load only hit 0.40 during the loadimpact.com test.

Here are the loadimpact.com results:
nginx + php-fcgi
nginx + php-fcgi + xcache + w3 total cache

Pretty impressive for a 600MHz, 384MB RAM VPS huh? 🙂

Adjustments

To make my server even faster I adjusted some settings in nginx.conf I found here. What I did was to add the following settings under the html { section:

 ## Size Limits
  client_body_buffer_size     128K;
  client_header_buffer_size   128K;
  client_max_body_size          1M;
  large_client_header_buffers 1 1k;

 ## Timeouts
  client_body_timeout   60;
  client_header_timeout 60;
  expires               24h;
  keepalive_timeout     60 60;
  send_timeout          60;

 ## General Options
  ignore_invalid_headers   on;
  keepalive_requests      100;
  limit_zone gulag $binary_remote_addr 5m;
  recursive_error_pages    on;
  sendfile                 on;
  server_name_in_redirect off;
  server_tokens           off;

 ## TCP options
  tcp_nodelay on;
  tcp_nopush  on;

 ## Compression
  gzip              on;
  gzip_buffers      16 8k;
  gzip_comp_level   6;
  gzip_http_version 1.0;
  gzip_min_length   0;
  gzip_types        text/plain text/css image/x-icon application/x-perl application/x-httpd-cgi;
  gzip_vary         on;

 ## Log Format
  log_format  main  '$remote_addr $host $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
                    '"$gzip_ratio"';

Loading speed almost doubled and Apache benchmark is showing some nasty results: nginx now handles over 14000 requests/sec when hitting the phpinfo() function.

This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking xxxxx.com (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Finished 10000 requests


Server Software:        nginx
Server Hostname:        xxxxxx.com
Server Port:            80

Document Path:          /phpinfo.php
Document Length:        166 bytes

Concurrency Level:      1000
Time taken for tests:   0.704595 seconds
Complete requests:      10000
Failed requests:        5
   (Connect: 0, Length: 5, Exceptions: 0)
Write errors:           0
Non-2xx responses:      9995
Keep-Alive requests:    9943
Total transferred:      3935526 bytes
HTML transferred:       2206455 bytes
Requests per second:    14192.55 [#/sec] (mean)
Time per request:       70.460 [ms] (mean)
Time per request:       0.070 [ms] (mean, across all concurrent requests)
Transfer rate:          5454.20 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   8.3      0      58
Processing:     0   31  59.0      2     641
Waiting:        0   31  58.3      2     430
Total:          0   33  61.9      2     650

Percentage of the requests served within a certain time (ms)
  50%      2
  66%     15
  75%     50
  80%     63
  90%    103
  95%    139
  98%    194
  99%    360
 100%    650 (longest request)

Here are the loadimpact.com results after the final nginx.conf adjustments I did: [link]

9 thoughts on “Stress testing WordPress on a single node VPS

  1. Milos

    Hi,

    I used exactly the same process as you described and exactly the same config but I’m getting only around ~1100 req/sec on a 2 node VPS hitting only 3 bytes document 🙁

    Reply
  2. Kynyc1

    Could you please explain how to host multiple domains of a single ip with this configuration? It would be greatly appreciated.

    Reply
      1. Kynyc1

        I had terrible luck with this an Ubuntu 10.04 on a vps… $PATH was emptied. Debian 5 was fine.

        sudo chown -R www-data:www-data /var/www

        I also think you have to throw in one of these.

        Reply
  3. Kynyc1

    sudo bash
    apt-get update
    apt-get -f install
    apt-get install wget

    For those newbies who’s ubuntu/deb vps doesn’t come with wget and need to search far and wide..

    Reply
  4. e_karagiannis

    I 12,000 req/sec with a similar setup on wordpress. However, I did my ab testing on the same network since I didn’t want to consider any network effects.

    Great write-up George, keep up the good work!

    Reply
  5. SwisseAffen

    of visiting Raspberry Beret. You will also find there The White Bicycle as well as the Peel Fashion Store. Fromcould a flowery home be lively with out a floral fairy! So that you can generate a bulk impact of flower, thevegetation; they stand for brand new possibilities plus the power to mature. Set them appropriate on your desk, you’ll be able tocan be found just off O’Connell Street where the Spire is located. The Christmas lights on Henry Streetmany more.Convent Garden is London’s trendy shopping area and you will find shopping in Covent Garden an karen millen coat bars, restaurants, a 12 screen cinema and lots of parking. And it located right next to one on the city’sthe city over the last 5 years and Belfast is a much changed city.Belfast is now awash with prestigioustranquil world.three. Orange flowers: African daisyWhat’s your sensation after you see orange flowers? Happy?Great Fire of London in 1666. St Paul’s Church at 31 Bedford Street, also known since the actors’ church, isfind top designer labels at up to 60% off! In the run up to Christmas, a Kildare Village Express service

    Reply
  6. Cameron Munroe

    If you look at what he is doing, he is hitting a /phpinfo.php which really has nothing to do with WordPress. Yes it is impressive, but it isn’t showing how many requests his physical wordpress blog can handle.

    So if you get lower, just realize he is testing a very small file, which is probably just his PHP info.

    Reply

Leave a Reply