/ nginx

Speed up your Wordpress site with a cache system

I was reading articles about caching systems for Wordpress, and I found many conflicting opinions: or completely pro cache or absolutely against cache framework.

I then decided to make a simple test to verify if it was really useful to have a cache on this blog (I've W3 Total Cache installed since the beginning) and here you are the results...

NB. On my nginx web server I've gzip activated on both tests with a browser cache for all static files.

Without cache

 MacBook-Pro-di-Marco:~ mmornati$ ab -n 100 -c5 http://blog.mornati.net/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.mornati.net (be patient).....done

Server Software:        nginx/1.4.3
Server Hostname:        blog.mornati.net
Server Port:            80

Document Path:          /
Document Length:        55299 bytes

Concurrency Level:      5
Time taken for tests:   65.994 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      5576900 bytes
HTML transferred:       5529900 bytes
Requests per second:    1.52 [#/sec] (mean)
Time per request:       3299.694 [ms] (mean)
Time per request:       659.939 [ms] (mean, across all concurrent requests)
Transfer rate:          82.53 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      173  321  79.4    317     483
Processing:  1676 2906 587.0   2845    4604
Waiting:     1068 2113 596.4   2058    3726
Total:       2038 3226 577.0   3178    4947

Percentage of the requests served within a certain time (ms)
  50%   3178
  66%   3424
  75%   3673
  80%   3720
  90%   3873
  95%   4160
  98%   4779
  99%   4947
 100%   4947 (longest request)

With W3C Total Cache

 MacBook-Pro-di-Marco:~ mmornati$ ab -n 100 -c5 http://blog.mornati.net/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.mornati.net (be patient).....done

Server Software:        nginx/1.4.3
Server Hostname:        blog.mornati.net
Server Port:            80

Document Path:          /
Document Length:        55619 bytes

Concurrency Level:      5
Time taken for tests:   2.994 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      5640878 bytes
HTML transferred:       5617244 bytes
Requests per second:    33.40 [#/sec] (mean)
Time per request:       149.717 [ms] (mean)
Time per request:       29.943 [ms] (mean, across all concurrent requests)
Transfer rate:          1839.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       16   21   2.6     21      29
Processing:    81  125  18.5    121     186
Waiting:       34   54  15.3     52     105
Total:        105  145  18.4    141     207

Percentage of the requests served within a certain time (ms)
  50%    141
  66%    148
  75%    155
  80%    158
  90%    169
  95%    184
  98%    200
  99%    207
 100%    207 (longest request)

I think the results are impressive:

4947 vs 207 ms = 2289,855% better with the cache activate

You have to set correctly your Wordpress cache framework to prevent caching problems; for example, new post not shown on the homepage... but, I think you should have a caching framework on a wordpress website!

If you decide to use it with the NGINX web server, here you are my configuration.

 server {
    listen 5.135.145.38:80;
    server_name blog.mornati.net;

    root /usr/share/nginx/blog;
    index               index.php index.html index.htm;

    access_log /var/log/nginx/blog.access.log;
    error_log /var/log/nginx/blog.error.log;

    # Use gzip compression
    # gzip_static       on;  # Uncomment if you compiled Nginx using --with-http_gzip_static_module
    gzip                on;
    gzip_disable        "msie6";
    gzip_vary           on;
    gzip_proxied        any;
    gzip_comp_level     5;
    gzip_buffers        16 8k;
    gzip_http_version   1.0;
    gzip_types          text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/png image/gif image/jpeg;

    # Rewrite minified CSS and JS files
    location ~* \.(css|js) {
        if (!-f $request_filename) {
            rewrite ^/wp-content/w3tc/min/(.+\.(css|js))$ /wp-content/w3tc/min/index.php?file=$1 last;
            # Use the following line instead for versions of W3TC pre-0.9.2.2
            # rewrite ^/wp-content/w3tc/min/([a-f0-9]+)\/(.+)\.(include(\-(footer|body))?(-nb)?)\.[0-9]+\.(css|js)$ /wp-content/w3tc/min/index.php?tt=$1&gg=$2&g=$3&t=$7 last;
        }
    }

    # Set a variable to work around the lack of nested conditionals
    set $cache_uri $request_uri;

    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
        set $cache_uri 'no cache';
    }
    if ($query_string != "") {
        set $cache_uri 'no cache';
    }

    # Don't cache uris containing the following segments
    if ($request_uri ~* "(\/wp-admin\/|\/xmlrpc.php|\/wp-(app|cron|login|register|mail)\.php|wp-.*\.php|index\.php|wp\-comments\-popup\.php|wp\-links\-opml\.php|wp\-locations\.php)") {
        set $cache_uri "no cache";
    }

    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp\-postpass|wordpress_logged_in") {
        set $cache_uri 'no cache';
    }

    # Use cached or actual file if they exists, otherwise pass request to WordPress
    location / {
        try_files /wp-content/w3tc/pgcache/$cache_uri/_index.html $uri $uri/ /index.php?q=$uri&$args;
    }

    # Cache static files for as long as possible
    location ~* \.(xml|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
        try_files       $uri =404;
        expires         max;
        access_log      off;
    }

    # Deny access to hidden files
    location ~* /\.ht {
        deny            all;
        access_log      off;
        log_not_found   off;
    }

    # Pass PHP scripts on to PHP-FPM
    location ~* \.php$ {
        try_files       $uri /index.php;
        fastcgi_index   index.php;
        fastcgi_pass    127.0.0.1:9000;
        include         fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
    }

}