<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>John Leach's Blog &#187; lua</title>
	<atom:link href="http://johnleach.co.uk/words/archives/tag/lua/feed" rel="self" type="application/rss+xml" />
	<link>http://johnleach.co.uk/words</link>
	<description>Stuff I think, see and do</description>
	<lastBuildDate>Fri, 18 Jun 2010 22:57:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Maintenance pages status codes and Lighttpd</title>
		<link>http://johnleach.co.uk/words/archives/2007/01/10/251/maintenance-pages-status-codes-and-lighttpd</link>
		<comments>http://johnleach.co.uk/words/archives/2007/01/10/251/maintenance-pages-status-codes-and-lighttpd#comments</comments>
		<pubDate>Wed, 10 Jan 2007 14:59:42 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Networks and Firewalls]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[mod_magnet]]></category>

		<guid isPermaLink="false">http://johnleach.co.uk/words/archives/2007/01/10/251/</guid>
		<description><![CDATA[I&#8217;ve noticed a few very broken maintenance page Lighttpd config examples around, including the one on the mod_magnet documentation page. They all manage to display the maintenance page ok, but they return a HTTP 200 status code to the client, rather than the more appropriate HTTP 503 code. As with all 500 status codes, the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve noticed a few very broken maintenance page Lighttpd config examples around, including the one on the mod_magnet documentation page.  They all manage to display the maintenance page ok, but they return a HTTP 200 status code to the client, rather than the more appropriate HTTP 503 code.</p>
<p>As with all 500 status codes, the 503 code is an error code but it signifies a <strong>temporary</strong> error.  The client should try again later (in fact you can specify how much later using the <code>Retry-After</code> header).</p>
<p>A 200 code tells the client everything is normal and OK.  So the user gets your nice maintenance page telling them of a temporary outage, whereas their browser gets told that <strong>everything is fine</strong>.  Now this might not be a problem for a user, but if the client is a <strong>search engine</strong> or a <strong>caching proxy</strong> then it will assume the maintenance page is the new valid content for the request.</p>
<p>If the Google crawler hits your site when you have the maintenance page up, it will update its search index with your &#8220;we&#8217;re down for now&#8221; message, rather than your cash prizes blog content.  Your page rank will drop, your fat Adsense cheque will diminish and you&#8217;ll have to go back to your regular nine to five job in the city with people you don&#8217;t like in clothes you hate wearing.</p>
<p>So, as you can see, it&#8217;s important to return the correct status code.  Here&#8217;s how to do it with Lighty and mod_magnet:</p>
<p><span id="more-251"></span></p>
<h3>Mod_magnet</h3>
<p>Mod_magnet allows you to control request handling in Lighttpd using the Lua programming language (it replaces mod_cml and adds some bells and whistles).  Here&#8217;s how to do a maintenance page with it:</p>
<p>Ensure the module is loaded:</p>
<pre><code>server.modules += ("mod_magnet")
</code></pre>
<p>Tell it where to find your Lua script:</p>
<pre><code>magnet.attract-physical-path-to = (server.docroot + "/magnet.lua")</code></pre>
<p>Write a lua script to check for the maintenance page file and display it instead of the usual content if it exists.</p>
<pre><code>if (lighty.stat(lighty.env["physical.doc-root"] .. "/maintenance-live.html")) then
                lighty.content = { { filename = lighty.env["physical.doc-root"] .. "/maintenance-live.html" } }
                lighty.header["Content-Type"] = "text/html"
        return 503
end
</code></pre>
<p>Create your maintenance page as <code>maintenance.html</code> in your document root.  When you want it displayed, symlink it to <code>maintenance-live.html</code> and it will automatically be displayed.</p>
<p>I find it useful to be able to switch back and forth easily without restarts in and around the actual maintenance period but don&#8217;t need it day to day.  So if you worry about the extra file stat operation (and the Lua) overhead during normal periods then just comment the Lua code out when you&#8217;re done with the maintenance feature for a while.  mod_magnet will detect that you modified the Lua script and recompile it automatically.</p>
<p>You&#8217;ll notice that the <code>return 503</code> actually returns a pre-generated HTML page as well as setting the status code.  This extra bit of html gets tagged onto the end of your nice maintenance page, making it a bit ugly.  You&#8217;ll just have to put up with this for now. I see this as a bug in Lighty which needs addressing.  There should be some way to set a status code with Lua without returning the pre-generated html too.</p>
<h3>Debug access</h3>
<p>It might be convenient to disable the maintenance page for certain client IP addresses: if you&#8217;re upgrading the site, you&#8217;ll want to test it&#8217;s working yourself before disabling the maintenance page, right?  I couldn&#8217;t figure out how to get the source address from within the Lua script, so I did it as a conditional in the Lighty config:</p>
<pre><code>  $HTTP["remoteip"] != "10.0.0.1" {
    magnet.attract-physical-path-to = ( server.document-root + "/magnet.lua" )
  }
</code></pre>
<p>Using mod_magnet might be overkill for just this task, but if you&#8217;re already using it for other request processing stuff, then it&#8217;s ideal for this.  Or maybe its convenience will be enough to sway you.  Just remember to get the status code right!</p>
<p>See nixCraft for <a href="http://www.cyberciti.biz/tips/howto-disable-site-for-maintenance-with-503-error.html">another example using PHP</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnleach.co.uk/words/archives/2007/01/10/251/maintenance-pages-status-codes-and-lighttpd/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>High performance WordPress</title>
		<link>http://johnleach.co.uk/words/archives/2006/06/05/223/high-performance-wordpress</link>
		<comments>http://johnleach.co.uk/words/archives/2006/06/05/223/high-performance-wordpress#comments</comments>
		<pubDate>Mon, 05 Jun 2006 15:30:09 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[eaccelerator]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[mod_cml]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp-cache]]></category>

		<guid isPermaLink="false">http://johnleach.co.uk/words/archives/2006/06/05/223/</guid>
		<description><![CDATA[Of all the WordPress installations I manage, two of them bring in a rather large number of hits. To speed up WordPress I usually just enable the MySQL query cache and install the eaccelerator PHP opcode cacher. On one particular box, an Intel 1.3Ghgz PIII this increased performance from around 3 requests per second to [...]]]></description>
			<content:encoded><![CDATA[<p>Of all the WordPress installations I manage, two of them bring in a rather large number of hits.</p>
<p>To speed up WordPress I usually just enable the MySQL query cache and install the eaccelerator PHP opcode cacher.  On one particular box, an Intel 1.3Ghgz PIII this increased performance from around 3 requests per second to around 10.</p>
<p>Recently I came across the <a href="http://mnm.uib.es/gallir/wp-cache-2/">WP-Cache plugin</a> for WordPress.  This takes the finished output from any given wordpress request and caches it to disk, serving directly from the static cache for the next hour (configurable).  Any new posts or comments in the mean time immediately mark the cached version stale, so you don&#8217;t need to wait around for an hour.</p>
<p>On the same hardware and blog, this increases performance from 10 requests per second to over 250.  <strong>A 2500% increase in speed.</strong><br />
<span id="more-223"></span></p>
<h3>Lighttpd cache meta language</h3>
<p>With WP-Cache, each request still has to incur the penalty of a PHP script execution, even though it&#8217;s much shorter one than the usual WordPress path.  Lighttpd now has a <a href="http://www.lighttpd.net/documentation/cml.html">mod_cml plugin</a> which allows you to script caching decisions in a language called <a href="http://www.lua.org/">Lua</a>, directly in the web server.</p>
<p>One should be able to implement enough WP-Cache logic with Lua so that Lighttpd can serve the cached static html directly, only executing PHP when the cache is stale.</p>
<p>Looking at the WP-Cache code, all that&#8217;s needed is a md5sum hash of the request url and a file modification time check, which seems to be possible in Lua in mod_cml.</p>
<p>The only thing that can&#8217;t be done is reading cache files for users with login or comment name cookies, as mod_cml doesn&#8217;t seem to provide access to cookies.  This would still increase the performance for the majority of requests though.</p>
<p>I&#8217;ve not had time to write and test a Lua script yet though.</p>
<h2>Apache Bench results</h2>
<h3>Before WP-Cache</h3>
<pre><code>This is ApacheBench, Version 2.0.41-dev
Server Software:        lighttpd/1.4.11
Server Hostname:        geekz.co.uk
Document Path:          /lovesraymond/archive/terrorismistic
Document Length:        16004 bytes
Concurrency Level:      3
Time taken for tests:   4.861144 seconds
Complete requests:      50
Total transferred:      818266 bytes
HTML transferred:       808270 bytes
Requests per second:    10.29 [#/sec] (mean)
Time per request:       291.669 [ms] (mean)
Time per request:       97.223 [ms] (mean, across all)
Transfer rate:          164.36 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    92  118  91.1     94     649
Waiting:       67   84  54.6     69     393
Total:         92  118  91.1     94     649

Percentage of the requests served within a certain time (ms)
  50%     94
  66%     95
  75%     97
  80%     98
  90%    155
  95%    217
  98%    649
  99%    649
 100%    649 (longest request)</code></pre>
<h3>After WP-Cache</h3>
<p>I had to run the test for longer else it was too quick for reliable results (and higher concurrency too)</p>
<pre><code>This is ApacheBench, Version 2.0.41-dev
Server Software:        lighttpd/1.4.11
Server Hostname:        geekz.co.uk
Document Path:          /lovesraymond/archive/terrorismistic
Document Length:        16098 bytes
Concurrency Level:      5
Time taken for tests:   3.79451 seconds
Complete requests:      800
Total transferred:      13059990 bytes
HTML transferred:       12942792 bytes
Requests per second:    259.79 [#/sec] (mean)
Time per request:       19.247 [ms] (mean)
Time per request:       3.849 [ms] (mean, across all)
Transfer rate:          4141.32 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    6   5.0      7      22
Processing:     4   11   6.5     11      67
Waiting:        0    7   6.2      7      61
Total:         16   18   4.1     18      80

Percentage of the requests served within a certain time (ms)
  50%     18
  66%     18
  75%     18
  80%     18
  90%     19
  95%     19
  98%     24
  99%     34
 100%     80 (longest request)
</code></pre>
<h3>WP-Cache and PHP 5.1 bug workaround</h3>
<p>Just a quick note, I use PHP 5.1 and came across a bug in WP-Cache that displayed blank pages on first load.  It&#8217;s an easy one line fix <a href="http://wiki.dreamhost.com/index.php/WordPress#Blank_Pages">once you know how</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://johnleach.co.uk/words/archives/2006/06/05/223/high-performance-wordpress/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
