[SYSADMIN] Serve your WordPress cached pages directly with lighttpd and not PHP

Optimizing Your WordPress Cache Loads in Lighttpd.

If you don’t configure your wordpress virtual host properly in lighttpd, your wordpress cache will still make use of PHP.

Wouldn’t it be nice if all those cached requests were served directy from the webserver as the static files that they are, bypassing the CPU/memory load PHP can have, and use those resources for otherthings?

Install and Enable mod_magnet

For this to occur with lighttpd, you will need mod_magnet, so assuming you’re on a Ubuntu/Debian based linux distro let’s make sure we have it installed.

sudo apt-get install lighttpd-mod-magnet

Then let’s make sure it’s enabled, you can do this manually on your lighttpd.conf by adding “mod_magnet” to the list of enabled modules…

server.modules = (
        "mod_fastcgi",
        "mod_access",
        "mod_alias",
        "mod_accesslog",
        "mod_compress",
        "mod_rewrite",
        "mod_redirect",
        "mod_status",
        "mod_proxy",
        "mod_setenv",
        "mod_magnet"
)

or you can do it the lighty way:

sudo lighty-enable-mod magnet

(this simply makes a symlink to the 10-magnet.conf file inside /etc/lighttpd/conf-enabled which lighty will check upon startup)

The cache logic script that will be executed by lighttpd

Now, on your wordpress directory, create a file called rewrite.lua and paste the following script in it:

function log(str)
   -- wanna tail -f a log to see what's happening    
   fp = io.open("/path/to/some/lua.log","a+")
   fp:write(str .. "\n")
   fp:flush()
   fp:close()
end

function serve_html(cached_page)
    if (lighty.stat(cached_page)) then
        lighty.env["physical.path"] = cached_page
        return true
    else
        return false
    end
end

function serve_gzip(cached_page)
    if (lighty.stat(cached_page .. ".gz")) then
        lighty.header["Content-Encoding"] = "gzip"
        lighty.header["Content-Type"] = ""
        lighty.env["physical.path"] = cached_page .. ".gz"
        return true
    else
        return false
    end
end

if (lighty.env["uri.scheme"] == "http") then
    ext = ".html"
else
    ext = "-https.html"
end

cached_page = lighty.env["physical.doc-root"] .. "/wp-content/cache/supercache/" .. lighty.request["Host"] .. lighty.env["request.orig-uri"]
cached_page = string.gsub(cached_page, "//", "/")
cached_page = string.gsub(cached_page, lighty.request["Host"] .. "/index.php", lighty.request["Host"])

attr = lighty.stat(cached_page)

if (attr) then
    query_condition = not (lighty.env["uri.query"] and string.find(lighty.env["uri.query"], ".*s=.*"))
    user_cookie = lighty.request["Cookie"] or "no_cookie_here"
    cookie_condition = not (string.find(user_cookie, ".*comment_author.*") or (string.find(user_cookie, ".*wordpress.*") and not string.find(user_cookie,"wordpress_test_cookie")))

    if (query_condition and cookie_condition) then
        accept_encoding = lighty.request["Accept-Encoding"] or "no_acceptance"

        if (string.find(accept_encoding, "gzip")) then
            if not serve_gzip(cached_page) then 
                serve_html(cached_page) 
            end
        else
            serve_html(cached_page)
        end
        --log('cache-hit: ' .. cached_page)
    end
else
    --log('cache-miss: ' .. cached_page)
end

Configuring your vhost in lighttpd for WordPress redirects and direct cache serves without php.

Then on your vhost configuration in lighttpd.conf add the following towards the end.
(Fix paths if you have to)

var.wp_blog = 1

magnet.attract-physical-path-to = ( server.document-root + "/rewrite.lua" )

url.rewrite-if-not-file = (
   "^/(wp-.+).*/?" => "$0",
   "^/(sitemap.xml)" => "$0",
   "^/(xmlrpc.php)" => "$0",
   "^/(.+)/?$" => "/index.php/$1"
  )

Restart your lighttpd sudo service lighttpd restart

Now watch how your PHP processes breathe a lot better and you page loads are insanely faster.

You’re welcome 🙂

Checking the Speed of your network interface

I recently requested an upgrade on one of our dedicated server’s uplink speed, we only had a 10Mbps Uplink, we requested an upgrade to 100Mbps to serve a lot more.

How do you verify the upgrade has been done correctly?

As root, issue the following comand:

# mii-tool
eth0: negotiated 10baseT-FD, link ok

If it doesn’t work (for debian or ubuntu), make sure you have installed the net-tools package (The NET-3 networking toolkit)

New Safari’s JavaScript engine Kicks Ass!

So I downloaded yesterday the latest Software Update for Mac OSX and it included an update of the Safari Web Browser, which I had taken for dead ages ago, I’m a hardcore Firefox user.

Today I read about the new updates, and I read something that caught my eye at Mackinando.com.

it executes JavaScript six times faster than the rest

I go to the Safari Site, and they compare themselves with a previous version, Firefox, and Opera (not IE, not even worth mentioning)

I couldn’t believe my eyes, so I googled for “JavaScript Benchmark“, and tried the SunSpider JavaScript Benchmark onboth Firefox 2.0.0.12 and the shiny new Safari 3.1.

The machine used for this test is a MacBook Pro running Mac OS X Version 10.4.11 with a 2.33 GHz Intel Core 2 Duo and 2GB 667 MHz DDR2 SDRAM.

Here are the results side by side:

FIREFOX 2.0.0.12
========================
RESULTS 
(means and 95% confidence intervals)
-----------------------------------------
Total:                 15365.4ms +/- 1.7%
-----------------------------------------

  3d:                   2386.6ms +/- 7.9%
    cube:                733.0ms +/- 20.8%
    morph:              1269.8ms +/- 9.4%
    raytrace:            383.8ms +/- 37.1%

  access:               1386.2ms +/- 4.8%
    binary-trees:        201.6ms +/- 0.6%
    fannkuch:            294.8ms +/- 5.4%
    nbody:               691.2ms +/- 8.9%
    nsieve:              198.6ms +/- 1.5%

  bitops:               3461.2ms +/- 0.4%
    3bit-bits-in-byte:   275.8ms +/- 0.6%
    bits-in-byte:        248.2ms +/- 0.7%
    bitwise-and:        2765.2ms +/- 0.5%
    nsieve-bits:         172.0ms +/- 4.7%

  controlflow:           153.4ms +/- 0.7%
    recursive:           153.4ms +/- 0.7%

  crypto:                527.2ms +/- 0.5%
    aes:                 230.8ms +/- 1.2%
    md5:                 147.4ms +/- 0.5%
    sha1:                149.0ms +/- 0.6%

  date:                 2551.8ms +/- 0.3%
    format-tofte:       1449.6ms +/- 0.3%
    format-xparb:       1102.2ms +/- 0.8%

  math:                 1312.6ms +/- 12.8%
    cordic:              497.4ms +/- 12.0%
    partial-sums:        501.6ms +/- 1.6%
    spectral-norm:       313.6ms +/- 36.1%

  regexp:                501.0ms +/- 0.2%
    dna:                 501.0ms +/- 0.2%

  string:               3085.4ms +/- 10.3%
    base64:              914.6ms +/- 3.4%
    fasta:               676.0ms +/- 35.4%
    tagcloud:            441.4ms +/- 0.6%
    unpack-code:         846.8ms +/- 25.4%
    validate-input:      206.6ms +/- 1.1%
SAFARI 3.1
========================
RESULTS 
(means and 95% confidence intervals)
-----------------------------------------
Total:                 3368.8ms +/- 1.0%
-----------------------------------------

  3d:                   414.8ms +/- 1.9%
    cube:               132.2ms +/- 2.4%
    morph:              144.6ms +/- 4.1%
    raytrace:           138.0ms +/- 0.6%

  access:               520.4ms +/- 4.1%
    binary-trees:        78.6ms +/- 11.3%
    fannkuch:           231.4ms +/- 2.0%
    nbody:              149.2ms +/- 8.1%
    nsieve:              61.2ms +/- 3.9%

  bitops:               449.6ms +/- 2.4%
    3bit-bits-in-byte:   69.8ms +/- 9.6%
    bits-in-byte:        99.2ms +/- 4.6%
    bitwise-and:        167.2ms +/- 2.3%
    nsieve-bits:        113.4ms +/- 6.7%

  controlflow:           91.2ms +/- 4.7%
    recursive:           91.2ms +/- 4.7%

  crypto:               247.2ms +/- 2.3%
    aes:                 81.2ms +/- 2.5%
    md5:                 83.8ms +/- 4.6%
    sha1:                82.2ms +/- 2.0%

  date:                 306.4ms +/- 0.5%
    format-tofte:       146.6ms +/- 1.4%
    format-xparb:       159.8ms +/- 1.0%

  math:                 454.8ms +/- 1.3%
    cordic:             174.4ms +/- 1.6%
    partial-sums:       193.8ms +/- 1.2%
    spectral-norm:       86.6ms +/- 4.4%

  regexp:               209.6ms +/- 0.7%
    dna:                209.6ms +/- 0.7%

  string:               674.8ms +/- 2.2%
    base64:             103.8ms +/- 9.0%
    fasta:              177.0ms +/- 1.0%
    tagcloud:           136.0ms +/- 4.6%
    unpack-code:        136.0ms +/- 1.7%
    validate-input:     122.0ms +/- 2.6%

Comparing with Firefox, the overall result of this test was that it’s 4.56 times faster.

However, if we look test by test, there are areas where I feel embarrassed for Firefox.

Bitwise Operations
For example, Bit-Operation tests in Safari 3.1 are 7.7 times faster in Safari, being the case of the bitwise-AND (&) operator the worst of them, Safari performed bitwise-and’s 16 times faster than Firefox

OUCH!!

String Operations
So you’d be curious now about String operations, which is probably a lot of what goes on with Javascript, and Ajax, parsing those XML results and what not, maybe the bitwise & won’t hurt us that much given that not many programmers today are smart enough to use them for web programming.

When it comes to String operations, Safari 3.1 was 4.5 times faster than Firefox 2.

Kudos to the Safari Team, I thought there was no point in having Safari until I did this benchmark. I guess they don’t want to let go of Web Browser users, maybe they make millions every month with ad-clicks on Google generated with the search field they have at the top of the browser which is set by default to do Google search.

Once again the saying proves it self

“Competition is good”

Let’s hope this will make the Firefox team think more on Javascript improvements with the upcoming Firefox 3. Once it’s release ready, it’ll be worth it running this benchmark again and see where it stands.

Update (March 20th, 2008)

I’ve made tests on Firefox 3 beta 4, You can see the results here. Tests have been made again on the same Macbook Pro. The improvements of Firefox 3 are notable, however, on the mac, Safari still wins.