<?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>Brain Matters &#187; Infrastructure</title>
	<atom:link href="http://blog.agoragames.com/category/engineering/infrastructure/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.agoragames.com</link>
	<description></description>
	<lastBuildDate>Thu, 29 Jul 2010 19:13:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Grabbing the Rabbit by the Horns</title>
		<link>http://blog.agoragames.com/2010/07/28/grabbing-the-rabbit-by-the-horns/</link>
		<comments>http://blog.agoragames.com/2010/07/28/grabbing-the-rabbit-by-the-horns/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 15:17:37 +0000</pubDate>
		<dc:creator>Aaron Westendorf</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=644</guid>
		<description><![CDATA[RabbitMQ is a very powerful tool, especially when deployed in a cluster.  Among RabbitMQ&#8217;s more useful features is rabbitmqctl, the command line tool which can be used to query a node and list its exchanges, queues, connections, number of consumers, memory usage and more.
The application, and cluster deployment in general, is hamstrung by Erlang&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>RabbitMQ is a very powerful tool, especially when deployed in a cluster.  Among RabbitMQ&#8217;s more useful features is rabbitmqctl, the command line tool which can be used to query a node and list its exchanges, queues, connections, number of consumers, memory usage and more.</p>
<p>The application, and cluster deployment in general, is hamstrung by Erlang&#8217;s standard approach to cookies.  The cookie, typically .erlang.cookie in the HOME directory of an application, must have only user read permissions.  For a Linux RabbitMQ install, that would look like this:</p>
<pre class="brush: text">
bofh@rabbit_host1:~$ ls -al /var/lib/rabbitmq/
total 333
drwxr-xr-x  3 rabbitmq rabbitmq    160 2010-07-12 17:49 .
drwxr-xr-x 37 root     root       1008 2010-07-02 14:29 ..
-r--------  1 rabbitmq rabbitmq     20 2010-05-04 20:44 .erlang.cookie
drwxr-xr-x  3 rabbitmq rabbitmq     72 2010-05-04 20:49 mnesia
-rw-r--r--  1 rabbitmq rabbitmq     27 2010-07-12 17:49 pids
</pre>
<p>Any variation on these permissions and Erlang will refuse to start.  The permissions requirement is embedded into Erlang itself, making it more or less impossible to work around.  This creates the following problems:</p>
<p></p>
<ul style="list-style-type: disc">
<li>You must copy this file (or its contents) to all hosts in the cluster</li>
<li>All users of rabbitmqctl must run it as sudo</li>
<li>All monitoring tools must also run as root or have sudo capability</li>
<li>You must have the cookie file present on the host running rabbitmqctl</li>
</ul>
<p>Given how powerful rabbitmqctl is, you will likely still want to limit access to it, but this can be readily accomplished with standard Unix permissions.  By expanding who can use it and where, your system administrator will be thrilled to reduce need for sudo access and your customers will be happy with the additional tools you can deploy to monitor your cluster and its clients to ensure that all is well, 24/7.</p>
<p>Thankfully, RabbitMQ&#8217;s scripts accept a lot of environment variables which can be passed into the Erlang runtime, and Erlang kindly provides a way to bypass the cookie file through a command line literal.  The scripts are all located in the scripts directory inside your RabbitMQ installation.</p>
<pre class="brush: text">
bofh@rabbit_host:~$ ls -ald `erl -eval &#039;io:format(&quot;~s~n&quot;, [code:lib_dir()])&#039; -s init stop -noshell`/rabbitmq-server*/scripts
drwxr-xr-x 2 root root 520 2010-07-21 14:47 /usr/local/lib/erlang/lib/rabbitmq-server-1.7.0/scripts
drwxr-xr-x 2 root root 520 2010-07-21 16:15 /usr/local/lib/erlang/lib/rabbitmq-server-1.7.2/scripts
</pre>
<p>The three standard scripts, rabbitmq-server, rabbitmq-multi and rabbitmqctl all source an environment script, rabbitmq-env, which in turn will source the file /etc/rabbitmq/rabbitmq.conf if it exists.  This is the file that you can edit to take control of your RabbitMQ cluster.</p>
<pre class="brush: bash">
SERVER_START_ARGS=&quot;+K true +A300 +P512000 -setcookie NOMNOMNOMYUMYUM -kernel inet_default_listen_options [{nodelay,true},{sndbuf,32768},{recbuf,32768}]&quot;
MULTI_START_ARGS=&quot;-setcookie NOMNOMNOMYUMYUM&quot;
CTL_ERL_ARGS=&quot;-setcookie NOMNOMNOMYUMYUM&quot;
</pre>
<p>The value of each environment variable will be passed verbatim to the Erlang runtime.  The SERVER_START_ARGS are passed to each node started by rabbitmq-multi, and directly affect the performance of a RabbitMQ instance.  In this example, we have increased the number of native threads available to Erlang and allowed it to spin up numerous (Erlang) processes.  We have also instructed the kernel to increase its TCP buffer sizes and disable Nagle's algorithm.</p>
<p>You can now run rabbitmqctl without sudo on any host which has this same configuration deployed.  This solution still requires that you synchronize /etc/rabbitmq across your cluster, though there are many ways of solving that problem.</p>
<p>We have taken this a step further and enabled rabbitmqctl on any host in our network.  All of our core software is deployed from source to /usr/local over NFS.  We have deployed the rabbitmq.conf file there too, and have a small shell script wrapping rabbitmqctl.</p>
<pre class="brush: bash">
#!/bin/bash
ERL_PATH=`erl -eval &#039;io:format(&quot;~s~n&quot;, [code:lib_dir()])&#039; -s init stop -noshell`
LATEST_VERSION=`ls $ERL_PATH | grep rabbitmq | sort | tail -1`
RABBIT_PATH=&quot;$ERL_PATH/$LATEST_VERSION&quot;

set -f
[ -f /usr/local/etc/rabbitmq/rabbitmq.conf ] &amp;&amp; . /usr/local/etc/rabbitmq/rabbitmq.conf
export CTL_ERL_ARGS
HOME=/var/lib/rabbitmq $RABBIT_PATH/scripts/rabbitmqctl $@
</pre>
<p>We can now connect to and monitor any RabbitMQ node from any host on our network</p>
<pre class="brush: text">
bofh@gateway:~$ rabbitmqctl -n rabbit@rabbit_host1 status
Status of node rabbit@rabbit_host1 ...
[{running_applications,[{rabbit,&quot;RabbitMQ&quot;,&quot;1.7.2&quot;},
                                {mnesia,&quot;MNESIA  CXC 138 12&quot;,&quot;4.4.10&quot;},
                                {os_mon,&quot;CPO  CXC 138 46&quot;,&quot;2.2.2&quot;},
                                {sasl,&quot;SASL  CXC 138 11&quot;,&quot;2.1.6&quot;},
                                {stdlib,&quot;ERTS  CXC 138 10&quot;,&quot;1.16.2&quot;},
                                {kernel,&quot;ERTS  CXC 138 10&quot;,&quot;2.13.2&quot;}]},
 {nodes,[rabbit@rabbit_host1,rabbit@rabbit_host2]},
 {running_nodes,[rabbit@rabbit_host1,rabbit@rabbit_host2]}]
...done.
</pre>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F07%2F28%2Fgrabbing-the-rabbit-by-the-horns%2F&amp;title=Grabbing%20the%20Rabbit%20by%20the%20Horns" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F07%2F28%2Fgrabbing-the-rabbit-by-the-horns%2F&amp;title=Grabbing%20the%20Rabbit%20by%20the%20Horns&amp;bodytext=RabbitMQ%20is%20a%20very%20powerful%20tool%2C%20especially%20when%20deployed%20in%20a%20cluster.%20%20Among%20RabbitMQ%27s%20more%20useful%20features%20is%20rabbitmqctl%2C%20the%20command%20line%20tool%20which%20can%20be%20used%20to%20query%20a%20node%20and%20list%20its%20exchanges%2C%20queues%2C%20connections%2C%20number%20of%20consumers%2C%20" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F07%2F28%2Fgrabbing-the-rabbit-by-the-horns%2F&amp;title=Grabbing%20the%20Rabbit%20by%20the%20Horns&amp;notes=RabbitMQ%20is%20a%20very%20powerful%20tool%2C%20especially%20when%20deployed%20in%20a%20cluster.%20%20Among%20RabbitMQ%27s%20more%20useful%20features%20is%20rabbitmqctl%2C%20the%20command%20line%20tool%20which%20can%20be%20used%20to%20query%20a%20node%20and%20list%20its%20exchanges%2C%20queues%2C%20connections%2C%20number%20of%20consumers%2C%20" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F07%2F28%2Fgrabbing-the-rabbit-by-the-horns%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/07/28/grabbing-the-rabbit-by-the-horns/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lifting the Tail: Inside Agora Skunk Works</title>
		<link>http://blog.agoragames.com/2010/06/28/lifting-the-tail-inside-agora-skunk-works/</link>
		<comments>http://blog.agoragames.com/2010/06/28/lifting-the-tail-inside-agora-skunk-works/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 13:08:25 +0000</pubDate>
		<dc:creator>Aaron Westendorf</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=623</guid>
		<description><![CDATA[We&#8217;ve been hard at work for over a year developing the next generation of game integration technology here at Agora, and over the next few months we&#8217;ll be releasing some of the code that we&#8217;ve developed, discussing some of the challenges we face and how we&#8217;re using all the new technology to build the best [...]]]></description>
			<content:encoded><![CDATA[<div id="_mcePaste">We&#8217;ve been hard at work for over a year developing the next generation of game integration technology here at Agora, and over the next few months we&#8217;ll be releasing some of the code that we&#8217;ve developed, discussing some of the challenges we face and how we&#8217;re using all the new technology to build the best gaming experience around.</div>
<p></p>
<div id="_mcePaste">To start, a brief explanation of the challenges we face.  As you might imagine, we deal with a lot of data.  The volume is only increasing, and with our friends at MLG, we expect significantly more of it.  Along with the volume of data, it also comes to us in many different forms and protocols; sometimes it&#8217;s pushed to us, and sometimes we have to go fetch it.  We have to respond to any number of business decisions made by developers and publishers, adapt to developers&#8217; needs in a manner which does not negatively impact their schedule, and be a consistent and reliable partner to all our clients.  We have to deliver comprehensive documentation to both game and website developers, and our business relationships are aided by a consistent offering.</div>
<p></p>
<div id="_mcePaste">In the past, each game&#8217;s services would be its own Rails application.  We built a suite of re-usable components, but for each title we would have to re-write a lot of boiler-plate code and set up an entirely new suite of servers, complete with application hosts, web and caching proxies, databases and so on.  As our data throughput grew, we found that we needed to add additional components to our stack, such as Sparrow, to turn synchronous workloads into asynchronous ones.  Each project required extensive monitoring and reporting, an interactive console for viewing production data and testing staging code.</div>
<p></p>
<div id="_mcePaste">We were very successful, but found the business costs too high and that we were missing several features that were important to our long term strategy of being the best in the industry at game integration.  Our experience with a virtualized hosting environment opened our eyes to the possibilities of turning our data processing and web services loose on a commoditized, shared platform.</div>
<p></p>
<div id="_mcePaste">With a general set of requirements in hand, we set forth, and what we came away with has been incubating, gestating and flowering into a powerful toolset that has met all our expectations, and then some.</div>
<p></p>
<div id="_mcePaste">Our first task was to choose the core set of technologies and the basic processing scheme that we would be using.  After an exhaustive search, lots of hacking and whiteboard scribblings, we settled on the following key features:</div>
<p></p>
<div id="_mcePaste">
<ul style="list-style-type:circle;">
<li>Python for all application code</li>
<li><a href="http://www.amqp.org">AMQP</a>, via <a href="http://www.rabbitmq.com">RabbitMQ</a>, for all inter-process communication</li>
<li>MySQL, Tokyo Tyrant and memcache for data storage services</li>
<li>Protocol translators to bridge external traffic to AMQP via a simple binary protocol</li>
<li>libevent for as many as IO operation as possible</li>
</ul>
</div>
<p></p>
<div id="_mcePaste"><img class="alignnone" title="lifting the tail" src="http://blog.agoragames.com/wp-content/uploads/2010/06/lifting_the_tail.png " alt="" width="357" height="193" /></div>
<p></p>
<div>We chose Python from the suitable dyanmic languages primarily for its memory management and speed.  We were shifting to a single-threaded multi-process environment where memory costs are high and performance paramount, and Python has an extensive pedigree in this area.  We did choose to sacrifice some memory by adhering to a single-threaded model in order to keep the application stack simple and use the kernel for all context switching.</div>
<p></p>
<div id="_mcePaste">AMQP&#8217;s routing scheme gives us powerful tools to shard and aggregate traffic across our cluster.  We chose RabbitMQ because of its Erlang heritage, its performance, reliability, clustering capabilities and commercial support.  By splitting up each game&#8217;s services into discrete packages which can each run numerous instances, we can readily divide traffic across a cluster of RabbitMQ hosts and attach listeners for monitoring, diagnostics and metrics.  The dotted-notation of AMQP&#8217;s topic exchanges allow for routing traffic between titles, environments, services and even specific commands.</div>
<p></p>
<div>To get the most out of the kernel and reduce latency, we use <a href="http://monkey.org/~provos/libevent/">libevent</a> for all of our AMQP traffic and in our protocol translators.  We extensively patched the <a href="http://barryp.org/software/py-amqplib/">py-amqplib</a> to work within this asynchronous environment.  This fork has been in production use for some time now but is slated for a ground-up re-write and release into the wild.</div>
<p></p>
<div id="_mcePaste">We considered many other database solutions, but at the time that we had to make our decision, felt that Tokyo Tyrant was the best NoSQL database to introduce into our stack because of its sparse table capabilities, high performance, low resource usage and simple setup.  We&#8217;re very excited with all the new development that is taking place in this field, and will be writing more about our experience with these tools over the coming years.</div>
<p></p>
<div id="_mcePaste">What we ended up with has met all of the goals that we set out to achieve.  We have successfully abstracted scaling, monitoring, protocol presentation and metric aggregation, allowing us to focus entirely on delivering functionality to our customers.  Now that our customers include MLG, this means that we&#8217;ll be rolling out some of the biggest and baddest applications in the gaming community, with confidence and reliability.</div>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F06%2F28%2Flifting-the-tail-inside-agora-skunk-works%2F&amp;title=Lifting%20the%20Tail%3A%20Inside%20Agora%20Skunk%20Works" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F06%2F28%2Flifting-the-tail-inside-agora-skunk-works%2F&amp;title=Lifting%20the%20Tail%3A%20Inside%20Agora%20Skunk%20Works&amp;bodytext=We%27ve%20been%20hard%20at%20work%20for%20over%20a%20year%20developing%20the%20next%20generation%20of%20game%20integration%20technology%20here%20at%20Agora%2C%20and%20over%20the%20next%20few%20months%20we%27ll%20be%20releasing%20some%20of%20the%20code%20that%20we%27ve%20developed%2C%20discussing%20some%20of%20the%20challenges%20we%20face%20and%20" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F06%2F28%2Flifting-the-tail-inside-agora-skunk-works%2F&amp;title=Lifting%20the%20Tail%3A%20Inside%20Agora%20Skunk%20Works&amp;notes=We%27ve%20been%20hard%20at%20work%20for%20over%20a%20year%20developing%20the%20next%20generation%20of%20game%20integration%20technology%20here%20at%20Agora%2C%20and%20over%20the%20next%20few%20months%20we%27ll%20be%20releasing%20some%20of%20the%20code%20that%20we%27ve%20developed%2C%20discussing%20some%20of%20the%20challenges%20we%20face%20and%20" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F06%2F28%2Flifting-the-tail-inside-agora-skunk-works%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/06/28/lifting-the-tail-inside-agora-skunk-works/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>vBulletin and NGINX</title>
		<link>http://blog.agoragames.com/2010/03/11/vbulletin-and-nginx/</link>
		<comments>http://blog.agoragames.com/2010/03/11/vbulletin-and-nginx/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 19:27:34 +0000</pubDate>
		<dc:creator>Jason LaPorte</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vbulletin]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=504</guid>
		<description><![CDATA[It&#8217;s no secret that Agorian systems folk favor NGINX for our web serving needs. We&#8217;ve written about it a lot before. Therefore, it should be no surprise that we end up making a lot of things designed to work on Apache work on NGINX. (We&#8217;ve also written about that before, come to think of it&#8230;)
One [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s no secret that Agorian systems folk favor <a href="http://nginx.org/" target="_blank">NGINX</a> for our web serving needs. We&#8217;ve written about it a lot before. Therefore, it should be no surprise that we end up making a lot of things designed to work on <a href="http://httpd.apache.org/" target="_blank">Apache</a> work on NGINX. (We&#8217;ve also written about that before, come to think of it&#8230;)</p>
<p>One example is <a href="http://www.vbulletin.com/" target="_blank">vBulletin</a>. A number of Agora&#8217;s sites are powered by the forum software, which comes with rewriting rules for Apache&#8217;s <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html" target="_blank">mod_rewrite</a> and <a href="http://www.iis.net/" target="_blank">IIS</a>&#8230; but not NGINX.</p>
<p>So, if you&#8217;re interested in setting up vBulletin behind NGINX (and are using the advanced URL rewriting, like we are), you can find a sample configuration for doing so <a href="http://files.agoragames.com/jason/vb-nginx.txt" target="_blank">here</a>.</p>
<p>Let us know if you have any questions!</p>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F11%2Fvbulletin-and-nginx%2F&amp;title=vBulletin%20and%20NGINX" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F11%2Fvbulletin-and-nginx%2F&amp;title=vBulletin%20and%20NGINX&amp;bodytext=It%27s%20no%20secret%20that%20Agorian%20systems%20folk%20favor%20NGINX%20for%20our%20web%20serving%20needs.%20We%27ve%20written%20about%20it%20a%20lot%20before.%20Therefore%2C%20it%20should%20be%20no%20surprise%20that%20we%20end%20up%20making%20a%20lot%20of%20things%20designed%20to%20work%20on%20Apache%20work%20on%20NGINX.%20%28We%27ve%20also%20writt" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F11%2Fvbulletin-and-nginx%2F&amp;title=vBulletin%20and%20NGINX&amp;notes=It%27s%20no%20secret%20that%20Agorian%20systems%20folk%20favor%20NGINX%20for%20our%20web%20serving%20needs.%20We%27ve%20written%20about%20it%20a%20lot%20before.%20Therefore%2C%20it%20should%20be%20no%20surprise%20that%20we%20end%20up%20making%20a%20lot%20of%20things%20designed%20to%20work%20on%20Apache%20work%20on%20NGINX.%20%28We%27ve%20also%20writt" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F11%2Fvbulletin-and-nginx%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/03/11/vbulletin-and-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bzr to Git Migration</title>
		<link>http://blog.agoragames.com/2010/03/08/bzr-to-git-migration/</link>
		<comments>http://blog.agoragames.com/2010/03/08/bzr-to-git-migration/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 16:44:35 +0000</pubDate>
		<dc:creator>Abhishek Mukherjee</dc:creator>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[bzr]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=486</guid>
		<description><![CDATA[When I joined Agora, one of the first things I did was talk up git and how it&#8217;ll cure cancer, AIDS, and solve world peace. All at once. What that means for me is I&#8217;ve basically been tasked with the job of migrating anything that&#8217;s not git to git.
For some things these kinds of migration [...]]]></description>
			<content:encoded><![CDATA[<p>When I joined Agora, one of the first things I did was talk up <a href="http://git-scm.com">git</a> and how it&#8217;ll cure cancer, AIDS, and solve world peace. All at once. What that means for me is I&#8217;ve basically been tasked with the job of migrating anything that&#8217;s not git to git.</p>
<p>For some things these kinds of migration are first class citizens. Conveniently SVN, our old VCS is one of those. One of my new migrations was, less conveniently, <a href="http://bazaar.canonical.com/">Bazaar</a>. Now we have nothing against Bazaar at Agora. I mean my main personal open source project, <a href="http://exaile.org/">Exaile</a>, uses Bazaar. But we agreed we would rather only have one VCS in house.</p>
<p>After looking around and trying some fancy tools that didn&#8217;t work (read: tailor), I stumbled on a really quick solution that seems like it does everything necessary. Both Git and Bazaar (via plugins) support the fast-import/export format. I&#8217;m not sure about the mystic ways of how this format works but I do know it made my Bazaar repository a Git repository, and that makes me pleased.</p>
<h2>Getting the bzr plugin</h2>
<p>The first step would be to get the fast-import plugin for Bazaar from the launchpad mirror.</p>
<pre class="brush: bash">
mkdir -p ~/.bazaar/plugins
cd ~/.bazaar/plugins
bzr clone lp:bzr-fastimport fastimport
</pre>
<p>You can make sure it installed properly using a <code>bzr fast-export --help</code> and ensure that it doesn&#8217;t complain.</p>
<h2>Copy the repository</h2>
<p>Now that we have all the tools, time to copy it over</p>
<pre class="brush: bash">
mkdir ~/project.git
cd ~/project.git
git init
bzr fast-export --plain ~/path/to/bzr/branch | git fast-import
git checkout master  # only needed for a non-bare repository, like I made above
</pre>
<p>Wait a little while (or a long while if you&#8217;re testing the above code on a netbook for some reason like me). And that should be it.</p>
<p>I&#8217;m not sure how well this works with multiple Bazaar branches. There may be some crazy <code>--flags</code> on each side to make it work but running the code I put above on a full repo makes fast-export complain that I&#8217;m not pointing it to a valid branch. Please give us your comments if you know how to do this :). </p>
<p><strong>Update:</strong> Found out it was .bazaar not .bzr. My bad.</p>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F08%2Fbzr-to-git-migration%2F&amp;title=Bzr%20to%20Git%20Migration" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F08%2Fbzr-to-git-migration%2F&amp;title=Bzr%20to%20Git%20Migration&amp;bodytext=When%20I%20joined%20Agora%2C%20one%20of%20the%20first%20things%20I%20did%20was%20talk%20up%20git%20and%20how%20it%27ll%20cure%20cancer%2C%20AIDS%2C%20and%20solve%20world%20peace.%20All%20at%20once.%20What%20that%20means%20for%20me%20is%20I%27ve%20basically%20been%20tasked%20with%20the%20job%20of%20migrating%20anything%20that%27s%20not%20git%20to%20git.%0D%0A%0D%0A" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F08%2Fbzr-to-git-migration%2F&amp;title=Bzr%20to%20Git%20Migration&amp;notes=When%20I%20joined%20Agora%2C%20one%20of%20the%20first%20things%20I%20did%20was%20talk%20up%20git%20and%20how%20it%27ll%20cure%20cancer%2C%20AIDS%2C%20and%20solve%20world%20peace.%20All%20at%20once.%20What%20that%20means%20for%20me%20is%20I%27ve%20basically%20been%20tasked%20with%20the%20job%20of%20migrating%20anything%20that%27s%20not%20git%20to%20git.%0D%0A%0D%0A" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F03%2F08%2Fbzr-to-git-migration%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/03/08/bzr-to-git-migration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Watching Trees</title>
		<link>http://blog.agoragames.com/2010/02/23/watching-trees/</link>
		<comments>http://blog.agoragames.com/2010/02/23/watching-trees/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 13:43:00 +0000</pubDate>
		<dc:creator>Jason LaPorte</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[arcana]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=474</guid>
		<description><![CDATA[As a SysAdmin, my job more-or-less exists by knowing miscellaneous arcana that most software engineers aren&#8217;t aware of.
When a particular co-worker here at Agora has a problem with his Linux machine, I provide advice and show him how to fix it. Some months after he had joined Agora, I discovered that after each troubleshooting session, [...]]]></description>
			<content:encoded><![CDATA[<p>As a SysAdmin, my job more-or-less exists by knowing miscellaneous arcana that most software engineers aren&#8217;t aware of.</p>
<p>When a particular co-worker here at Agora has a problem with his Linux machine, I provide advice and show him how to fix it. Some months after he had joined Agora, I discovered that after each troubleshooting session, he copy-and-pastes the entire text terminal log into a text file that he keeps on his desktop. He has dozens of transcripts at this point; I bet if I were to look through it, it would read something like the Tao te Ching or Bhagavad Gita, only concerning UNIX instead of right living.</p>
<p>(Of course, there&#8217;s not much of a difference between UNIX and right living, but that&#8217;s a topic for another day.)</p>
<p>In the spirit of allowing you to build your own little collection, here is a simple trick that came in handy to me yesterday.</p>
<p><span id="more-474"></span>Last night, the cron jobs powering one of our managed sites stopped running. I had stopped them, cleaned up, and restarted them, but I wanted to watch the system and see if they had started running again so I could monitor that they were doing their job.</p>
<p>UNIX has a well-known command called &#8220;<a href="http://linux.die.net/man/1/top" target="_blank">top</a>,&#8221; which shows superlative processes running on your system: which ones are consuming the most CPU time, which ones are consuming the most RAM, which ones have been running the longest, and so on. It&#8217;s a very useful tool, but if you&#8217;re trying to track down processes over time that don&#8217;t necessarily consume very many resources, then it&#8217;s not the tool you&#8217;re looking for.</p>
<p>However, our Linux distribution (and, indeed, most others) provide a useful graphical tool for mapping the current state of the system: &#8220;<a href="http://linux.die.net/man/1/pstree" target="_blank">pstree</a>.&#8221; This command will give you a list of processes (much like the &#8220;<a href="http://linux.die.net/man/1/ps" target="_blank">ps</a>&#8221; command), except that instead of generating a list, it will draw a little tree showing the state of the system. This is perfect for seeing exactly what is going on: which daemons are running, who is on the system and what they&#8217;re executing, and so on. However, it doesn&#8217;t show you what is happening over time; it merely lists what is happening at this moment.</p>
<p>However, our Linux distribution (and, indeed, most others) provides yet another useful tool: &#8220;<a href="http://linux.die.net/man/1/watch" target="_blank">watch</a>.&#8221; It runs a program every 2 seconds (by default) and displays the result to your screen. This allows you to make a ghetto clock by writing something like &#8220;watch <a href="http://linux.die.net/man/1/date" target="_blank">date</a>;&#8221; in our case, we could make a ghetto graphical &#8220;top&#8221; by writing the simple &#8220;watch pstree.&#8221; You can now watch your virtual trees rustle in the wind.</p>
<p>It kept us on top of the cron job, and things were back to normal in no time.</p>
<p>For more information, RTFM. :)</p>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fwatching-trees%2F&amp;title=Watching%20Trees" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fwatching-trees%2F&amp;title=Watching%20Trees&amp;bodytext=As%20a%20SysAdmin%2C%20my%20job%20more-or-less%20exists%20by%20knowing%20miscellaneous%20arcana%20that%20most%20software%20engineers%20aren%27t%20aware%20of.%0D%0A%0D%0AWhen%20a%20particular%20co-worker%20here%20at%20Agora%20has%20a%20problem%20with%20his%20Linux%20machine%2C%20I%20provide%20advice%20and%20show%20him%20how%20to%20fix%20it.%20So" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fwatching-trees%2F&amp;title=Watching%20Trees&amp;notes=As%20a%20SysAdmin%2C%20my%20job%20more-or-less%20exists%20by%20knowing%20miscellaneous%20arcana%20that%20most%20software%20engineers%20aren%27t%20aware%20of.%0D%0A%0D%0AWhen%20a%20particular%20co-worker%20here%20at%20Agora%20has%20a%20problem%20with%20his%20Linux%20machine%2C%20I%20provide%20advice%20and%20show%20him%20how%20to%20fix%20it.%20So" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fwatching-trees%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/02/23/watching-trees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Experimenting with Redis</title>
		<link>http://blog.agoragames.com/2010/02/23/experimenting-with-redis/</link>
		<comments>http://blog.agoragames.com/2010/02/23/experimenting-with-redis/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 13:05:04 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[resque]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=470</guid>
		<description><![CDATA[Yesterday I started looking at ways to do inter-application communication. In a number of projects we&#8217;ve done here at Agora Games, we&#8217;ve used queues to make that happen. Redis has been on my radar for awhile now, but yesterday I drove my Chevy to the levee and guess what? The levee is NOT dry people. [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday I started looking at ways to do inter-application communication. In a number of projects we&#8217;ve done here at Agora Games, we&#8217;ve used queues to make that happen. <a href="http://code.google.com/p/redis/">Redis</a> has been on my radar for awhile now, but yesterday I drove my Chevy to the levee and guess what? The levee is NOT dry people. I mean, who drinks rye anyway these days? Old people.</p>
<p><span id="more-470"></span></p>
<p>Right, <a href="http://code.google.com/p/redis/">Redis</a>.</p>
<p>&#8220;Redis is an advanced key-value store. It is similar to memcached but the dataset is not volatile, and values can be strings, exactly like in memcached, but also lists, sets, and ordered sets. All this data types can be manipulated with atomic operations to push/pop elements, add/remove elements, perform server side union, intersection, difference between sets, and so forth. Redis supports different kind of sorting abilities.&#8221;</p>
<p>I was particularly interested in the support in Redis for lists, which would allow me to have one application push stuff into the datastore and allow for another application to pull stuff from the datastore. A datastore that could operate as a queue? I guess this is as close as we&#8217;re going to get to flying cars in 2010. Redis is also supposed to be wicked fast and there are a number of libraries available in your programming language of choice with which to communicate with Redis.</p>
<p>Redis setup was trivial and &#8220;just worked&#8221;.</p>
<p>After starting the Redis server, I could just prototype in script/console.</p>
<p>Here we go:</p>
<pre style="font-family: monospace;"><span>&gt;&gt;</span> redis_queue = Redis.<span>new</span>
<span>=&gt;</span> <span>#&lt;Redis:0x222df9c @thread_safe=nil, @logger=nil, @password=nil, @timeout=5, @db=0, @sock=nil, @host="127.0.0.1", @port=6379&gt;</span>
<span>&gt;&gt;</span> redis_queue.<span>push_tail</span> <span>'strings'</span>, <span>'string 1'</span>
<span>=&gt;</span> <span>"OK"
&gt;&gt; </span>redis_queue.<span>push_tail</span> <span>'strings'</span>, <span>'string 2'</span><span>
&gt;&gt;</span> <span>"OK"</span><span>
&gt;&gt;</span> redis_queue.<span>list_length</span><span>(</span><span>'strings'</span><span>)</span><span>
=&gt;</span> <span>2
&gt;&gt; </span>redis_queue.<span>list_range</span><span>(</span><span>'strings'</span>, <span>0</span>, <span>-</span><span>1</span><span>)</span>
=&gt; ["string 1", "string 2"]
&gt;&gt; some_string = redis_queue.pop_head('strings')
=&gt; "string 1"
&gt;&gt; r.list_range('strings', 0, -1)
=&gt; ["string 2"]
&gt;&gt; r.list_length('strings')
=&gt; 1
&gt;&gt; quit</pre>
<p><a href="http://code.google.com/p/redis/wiki/CommandReference">There are quite a few commands that make Redis even more awesome, but for now I&#8217;m sold</a>. (If using an entire sentence as a link is wrong then I don&#8217;t want to be right)</p>
<p>Also, I know of <a href="http://github.com/defunkt/resque#readme">Resque</a>, &#8220;a Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later.&#8221; If I ever feel like driving the Mercedes Benz of flying cars, I&#8217;ll use it.</p>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fexperimenting-with-redis%2F&amp;title=Experimenting%20with%20Redis" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fexperimenting-with-redis%2F&amp;title=Experimenting%20with%20Redis&amp;bodytext=Yesterday%20I%20started%20looking%20at%20ways%20to%20do%20inter-application%20communication.%20In%20a%20number%20of%20projects%20we%27ve%20done%20here%20at%20Agora%20Games%2C%20we%27ve%20used%20queues%20to%20make%20that%20happen.%20Redis%20has%20been%20on%20my%20radar%20for%20awhile%20now%2C%20but%20yesterday%20I%20drove%20my%20Chevy%20to%20the" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fexperimenting-with-redis%2F&amp;title=Experimenting%20with%20Redis&amp;notes=Yesterday%20I%20started%20looking%20at%20ways%20to%20do%20inter-application%20communication.%20In%20a%20number%20of%20projects%20we%27ve%20done%20here%20at%20Agora%20Games%2C%20we%27ve%20used%20queues%20to%20make%20that%20happen.%20Redis%20has%20been%20on%20my%20radar%20for%20awhile%20now%2C%20but%20yesterday%20I%20drove%20my%20Chevy%20to%20the" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F23%2Fexperimenting-with-redis%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/02/23/experimenting-with-redis/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>And now for some couchdb</title>
		<link>http://blog.agoragames.com/2010/02/22/and-now-for-some-couchdb/</link>
		<comments>http://blog.agoragames.com/2010/02/22/and-now-for-some-couchdb/#comments</comments>
		<pubDate>Tue, 23 Feb 2010 03:20:24 +0000</pubDate>
		<dc:creator>Brian Corrigan</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=460</guid>
		<description><![CDATA[I had occasion tonight to give a quick demo of CouchDB.  This is so simple its almost not worth blogging about, but hey, good software is supposed to be simple.
Install
On your Mac:

sudo port install couchdb
sudo launchctl load -w /Library/LaunchDaemons/org.apache.couchdb.plist

On Ubuntu:

sudo apt-get install couchdb

You&#8217;re done; now to play.
Futon Admin Interface
This allows you to create a DB, [...]]]></description>
			<content:encoded><![CDATA[<p>I had occasion tonight to give a quick demo of CouchDB.  This is so simple its almost not worth blogging about, but hey, good software is <strong><em>supposed</em></strong> to be simple.</p>
<p><strong>Install</strong><br />
On your Mac:</p>
<pre class="brush: bash">
sudo port install couchdb
sudo launchctl load -w /Library/LaunchDaemons/org.apache.couchdb.plist
</pre>
<p>On Ubuntu:</p>
<pre class="brush: bash">
sudo apt-get install couchdb
</pre>
<p>You&#8217;re done; now to play.</p>
<p><strong>Futon Admin Interface</strong><br />
This allows you to create a DB, create records, etc.</p>
<ol>
<li>Open http://localhost:5984/_utils/</li>
<li>&#8230;</li>
<li>Prosper</li>
</ol>
<p><strong>Using our old friend <em>curl</em></strong></p>
<pre class="brush: bash">
curl -X PUT http://localhost:5984/mlg/ #create a db
curl -X GET http://localhost:5984/mlg/ #get a whole bunch of info about the db
curl -X POST http://localhost:5984/mlg/ -H &quot;Content-Type:application/json&quot; -d &#039;{&quot;body&quot;: &quot;Here is a paragraph&quot;}&#039; #create a record
</pre>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F22%2Fand-now-for-some-couchdb%2F&amp;title=And%20now%20for%20some%20couchdb" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F22%2Fand-now-for-some-couchdb%2F&amp;title=And%20now%20for%20some%20couchdb&amp;bodytext=I%20had%20occasion%20tonight%20to%20give%20a%20quick%20demo%20of%20CouchDB.%20%C2%A0This%20is%20so%20simple%20its%20almost%20not%20worth%20blogging%20about%2C%20but%20hey%2C%20good%20software%20is%20supposed%20to%20be%20simple.%0D%0A%0D%0AInstall%0D%0AOn%20your%20Mac%3A%0D%0A%0D%0A%5Bsourcecode%20language%3D%27bash%27%5D%0D%0Asudo%20port%20install%20couchdb%0D%0Asud" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F22%2Fand-now-for-some-couchdb%2F&amp;title=And%20now%20for%20some%20couchdb&amp;notes=I%20had%20occasion%20tonight%20to%20give%20a%20quick%20demo%20of%20CouchDB.%20%C2%A0This%20is%20so%20simple%20its%20almost%20not%20worth%20blogging%20about%2C%20but%20hey%2C%20good%20software%20is%20supposed%20to%20be%20simple.%0D%0A%0D%0AInstall%0D%0AOn%20your%20Mac%3A%0D%0A%0D%0A%5Bsourcecode%20language%3D%27bash%27%5D%0D%0Asudo%20port%20install%20couchdb%0D%0Asud" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2010%2F02%2F22%2Fand-now-for-some-couchdb%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2010/02/22/and-now-for-some-couchdb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Large files with NGINX, GZip, and SSL</title>
		<link>http://blog.agoragames.com/2009/11/19/large-files-with-nginx-gzip-and-ssl/</link>
		<comments>http://blog.agoragames.com/2009/11/19/large-files-with-nginx-gzip-and-ssl/#comments</comments>
		<pubDate>Thu, 19 Nov 2009 18:47:04 +0000</pubDate>
		<dc:creator>Jeff</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=412</guid>
		<description><![CDATA[I ran into an interesting issue today when deploying a crappy password change app I wrote as an exercise in rails. It turns out that by default, NGINX has a gzip buffer size of 4 * 4k/8k, with the bit size depending on what platform the service is running on.
As a result,
4 * 4k = [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into an interesting issue today when deploying a crappy password change app I wrote as an exercise in rails. It turns out that by default, NGINX has a gzip buffer size of 4 * 4k/8k, with the bit size depending on what platform the service is running on.</p>
<p>As a result,</p>
<p>4 * 4k = 16384 bytes (16KB)<br />
4 * 8k = 32768 (32KB)</p>
<p>After gzip, when converted to be plain text, the amount of data returned to the browser nearly doubles (about 52KB in the case of larger). The default javascript library included by rails for AJAX (prototype.js) is 127k, which led me to find this limit.</p>
<p>And so, getting to the point, the limit applied to the gzip buffer needs to be increased within NGINX&#8217;s config files for each site that will use a file larger than these pre-set sizes. You can do so using the following:</p>
<p><strong>gzip_buffers 16 8k</strong></p>
<p><strong></strong><span style="font-weight: normal;">This will set the buffer size to 16 * 8k, or 128KB &#8212; the uncompressed size of the library, eliminating the issue.</span></p>
<p>In the future if you find NGINX truncating large files for no apparent reason, this is likely why.</p>
<p><strong><span style="font-weight: normal;">*EDIT* &#8212; In NGINX versions post 0.7.28, the default limit of gzip_buffers has been increased to 32 * 4 or 16 * 8 (rounding out to 128K, as noted above) depending on platform. It may be wise to double check any configs you may have to ensure you are not explicitly setting a lesser value, or upgrade NGINX if needed.<br />
</span></strong></p>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F11%2F19%2Flarge-files-with-nginx-gzip-and-ssl%2F&amp;title=Large%20files%20with%20NGINX%2C%20GZip%2C%20and%20SSL" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F11%2F19%2Flarge-files-with-nginx-gzip-and-ssl%2F&amp;title=Large%20files%20with%20NGINX%2C%20GZip%2C%20and%20SSL&amp;bodytext=I%20ran%20into%20an%20interesting%20issue%20today%20when%20deploying%20a%20crappy%20password%20change%20app%20I%20wrote%20as%20an%20exercise%20in%20rails.%20It%20turns%20out%20that%20by%20default%2C%20NGINX%20has%20a%20gzip%20buffer%20size%20of%204%20%2A%204k%2F8k%2C%20with%20the%20bit%20size%20depending%20on%20what%20platform%20the%20service%20is%20ru" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F11%2F19%2Flarge-files-with-nginx-gzip-and-ssl%2F&amp;title=Large%20files%20with%20NGINX%2C%20GZip%2C%20and%20SSL&amp;notes=I%20ran%20into%20an%20interesting%20issue%20today%20when%20deploying%20a%20crappy%20password%20change%20app%20I%20wrote%20as%20an%20exercise%20in%20rails.%20It%20turns%20out%20that%20by%20default%2C%20NGINX%20has%20a%20gzip%20buffer%20size%20of%204%20%2A%204k%2F8k%2C%20with%20the%20bit%20size%20depending%20on%20what%20platform%20the%20service%20is%20ru" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2009%2F11%2F19%2Flarge-files-with-nginx-gzip-and-ssl%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2009/11/19/large-files-with-nginx-gzip-and-ssl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spelunking into your logs with Splunk</title>
		<link>http://blog.agoragames.com/2009/10/12/spelunking-into-your-logs-with-splunk/</link>
		<comments>http://blog.agoragames.com/2009/10/12/spelunking-into-your-logs-with-splunk/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 18:56:16 +0000</pubDate>
		<dc:creator>Tim Jones</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[splunk]]></category>
		<category><![CDATA[syslog]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=383</guid>
		<description><![CDATA[At Agora we&#8217;re experimenting with Splunk as a error collection and reporting tool.  The idea is that all our services will spit out error information to syslog which will be picked up and indexed by Splunk.  Splunk will be configured to display info about recent errors, email summaries of those errors and generally be the [...]]]></description>
			<content:encoded><![CDATA[<p>At Agora we&#8217;re experimenting with Splunk as a error collection and reporting tool.  The idea is that all our services will spit out error information to syslog which will be picked up and indexed by Splunk.  Splunk will be configured to display info about recent errors, email summaries of those errors and generally be the starting point for discovering problems with our systems.  In our previous infrastructure error collection and reporting was handled on a per-project basis.  As we&#8217;re now moving to a more service oriented approach that involves a small number of generic but highly configurable services deployed over a large number nodes we needed something different.  Splunk seems ideal for this.  It accepts a number of different data sources ranging from syslog to raw log files to inputs from random UDP and TCP ports so we can easily integrate with systems we&#8217;ve written and, more importantly, those we haven&#8217;t.  It also has the summary and reporting capabilities we were looking for so we can chart errors over time periods, dig for trends and see which services are acting up.</p>
<p>The biggest problem I&#8217;ve had so far while working with Splunk is the documenation.  There are a lot of options and the documentation for those options is spread out over a number of distinct manuals.  Some options are poorly documented or not at all and often it&#8217;s not clear, even once you&#8217;ve found the proper option, where/how the option should be used.  The following is an attempt to lay out some of those problems I ran into and what the solutions are so you don&#8217;t have to go looking yourself.  This list will likely continue to grow over the coming weeks and months.</p>
<ol>
<li>
<p><strong>Extracting fields from search results</strong></p>
<p>Splunk automatically extracts certain fields from your search results.  This is all well and good but what if you want to pull out your own values?  As an example we stick a field into our syslog output that indicates what service the log entry came from.  This would be extremely handy since we&#8217;d then be able to filter out entries for a particular services, build charts with color coding based around the services and so on.  It turns out this is pretty easy.  Although this functionality is mentioned in the &#8216;User Manual&#8217; most of the ral documentation for the commands used can be found in the &#8216;Search Manual&#8217; (grrrr).  The portion in the User Manual can be found by search for &#8216;Extract fields with search commands&#8217;.  For the command information look for &#8216;rex&#8217; in the &#8216;Search Commands&#8217; section of the Search Reference.Anywho, the trick is in the &#8216;rex&#8217; command.  This can be chained onto your search request (something else that was not obvious) like many other Splunk commands:</p>
<p>
<pre>sourcetype="syslog" foo | rex field=_raw "[0-9a-z]{2} err \[(?&lt;service&gt;.*?)\]"</pre>
</p>
<p>The rex command takes a regular expression and produces fields based on matches.  The field option specifies which of Splunk&#8217;s default fields you want to match against (search in the Splunk manuals for &#8216;Use default and internal fields&#8217; for a list of all available fields).  The regex in this case matches two alphanumeric characters followed by the string &#8216;err&#8217; followed by a service name in brackets.  The ?&lt;service&gt; notation in parentheses indicates a match that should be saved in the &#8217;service&#8217; field.</p>
<p>Once your search has been executed you should see that you can now filter on whatever fields you extracted, create charts with them, etc.</p>
</li>
<li>
<p><strong>Extracting only those results that have a particular field</strong></p>
<p>So you&#8217;ve created a regex to extract certain fields from your result set but the results that don&#8217;t match your regex are still in the result set.  How do you filter those out?  The solution is actually pretty simple:</p>
<pre>&lt;your_original_search&gt; | rex &lt;your regex&gt; | search your_field="*"</pre>
<p>Likewise you can find those that didn&#8217;t match by negating the lookup:</p>
<p><code>
<pre>&lt;your_original_search&gt; | rex &lt;your regex&gt; | search NOT your_field="*"</pre>
<p></code></li>
<li>
<p><strong>Changing indices for search</strong></p>
<p>By default your searches will only hit the &#8216;main&#8217; index.  If you&#8217;ve created your own index it won&#8217;t be searched by default.  To use your index in a particular search just add it to the search string:</p>
<p><code>
<pre>index=my_index foo NOT bar</pre>
<p></code></p>
<p>To add your index to the default list so you don&#8217;t have to modify every search you&#8217;ll need to modify your roles a bit.  Visit the Roles page in the Manager, select your role (probably user or admin if you haven&#8217;t made any modifications here, and scroll down to the &#8216;Default indexes&#8217; list.</p>
</li>
<li>
<p><strong>Displaying the body of a message in an event table</strong></p>
<p>In our main dashboard we wanted to show a list of the 5 most recent errors.  This actually turned out to be more difficult than you might have expected.  The date, host, and a few other pieces of data showed up fine but for the life of me I couldn&#8217;t figure out how to get the body of the log message to show up in the table.  There is a special field called _raw for each result but adding that to the table had no effect.  In the end my solution was to create a regexp against my search results that extracted a parameter called &#8216;body&#8217;.</p>
<p>Search:</p>
<p><code>
<pre>sourcetype="syslog" err | rex field=_raw "[0-9a-z]{2} err \[(?&lt;service&gt;.*?)\] (?&lt;body&gt;.*)"</pre>
<p></code></p>
<p>Event Table:</p>
<p><code>
<pre>&lt;table&gt;
&lt;title&gt;Most recent service errors&lt;/title&gt;
&lt;searchName&gt;Service errors with body&lt;/searchName&gt;
&lt;option name="count"&gt;5&lt;/option&gt;
&lt;fields&gt;_time,host,body&lt;/fields&gt;
&lt;/table&gt;</pre>
<p></code></li>
<p>The events table:<br />
<img src="http://blog.agoragames.com/wp-content/uploads/2009/10/events.png" alt="events" width="801" height="247" class="alignnone size-full wp-image-402" /></p>
<li>
<p><strong>Changing the default app</strong></p>
<p>With a normal install the launcher is the default app.  This gets kind of annoying after a while.  To change it to your own app you can adjust the default_namespace option in $SPLUNK_HOME/etc/apps/user-prefs/local/user-prefx.conf.</p>
<p><code>
<pre>default_namespace = my_app</pre>
<p></code>
</li>
<li>
<p><strong>Email alerts</strong></p>
<p>Email alerts are built around scheduled searches.  When saving or editing a search you&#8217;re given the option to provide a schedule for it.  Change this option so that the search is run on some interval and additional options will appear including one to send an email alert.  Additionally you can modify the search to only include a certain time range.  These features are very handy when used in combination.  Schedule your search to run every 30 minutes and adjust the start time to -30m and you&#8217;ll get alerts about all errors that occurred during that time.</p>
<p>Mail settings themselves can be found in Manager -&gt; Email alert settings.</p>
</li>
<li>
<p><strong>Stacked time-based charts</strong></p>
<p>Took me a while to sort out this one.  The first thing you need to do is group your data into larger time periods.  If you have one column for each second your graph is going to be pretty useless.  Instead you should consolidate your data into large groups such as one per minute or one per hour.  I&#8217;ve found that dividing your time range by roughly 30 gives the best graphs.  To actually perform this grouping you need to add the &#8217;span&#8217; option to your search:</p>
<p><code>
<pre>sourcetype="syslog" foo NOT bar | timechart span=1h count</pre>
<p></code></p>
<p>This will produce a count of all the items containing foo and not bar for syslog in intervals of one hour.</p>
<p>Next you need to stack the resulting groups.  Annoyingly this is done at the view layer.  In my case I was adding it to my dashboard.  The relevant lines looked similar to the following:</p>
<p><code>
<pre>&lt;chart&gt;
&lt;searchName&gt;Service errors in the last 24 hours&lt;/searchName&gt;
&lt;title&gt;Service errors in the last 24 hours&lt;/title&gt;
&lt;option name="charting.chart"&gt;column&lt;/option&gt;
&lt;option name="charting.chart.stackMode"&gt;stacked&lt;/option&gt;
&lt;/chart&gt;</pre>
<p></code></p>
<p>There is a reference for all these options in the Splunk docs.  Search for &#8216;Custom charting configurations&#8217;.</p>
<p>The end result looks something like this:<br />
<img src="http://blog.agoragames.com/wp-content/uploads/2009/10/errors.png" alt="errors" width="804" height="245" class="alignnone size-full wp-image-400" /></p>
</li>
<li>
<p><strong>Edit everything manually</strong></p>
<p>The Splunk Manager interface is rather clunky (not entirely the developer&#8217;s fault, there are a lot of interdependent options) so after a while you&#8217;ll likely get sick of it.  That&#8217;s perfectly fine.  All the options are written out to config files per app.  All your changes are written out to $SPLUNK_HOME/etc/apps/&lt;your_app&gt;/local and override those options in $SPLUNK_HOME/etc/apps/&lt;your_app&gt;/default.  The default directory can be used as a handy reference for available options as well.  Note that some system wide options such as indices and roles are written out to $SPLUNK_HOME/etc/system/local.</p>
</li>
<li>
<p><strong>Don&#8217;t delete the &#8216;user&#8217; role</strong></p>
<p>If you do you&#8217;ll be sad as it breaks everything.  I&#8217;d attempted to remove the role and replace it with our own modified version.  The result was that every page I visited gave me a &#8220;Client not authorized&#8221; error.  To resolve the problem delete the &#8216;disabled = 1&#8242; line from $SPLUNK_HOME/etc/system/local/authorize.conf.</p>
</li>
<li>
<p><strong>Adding output to syslog(-ng)</strong></p>
<p>As mentioned previously our Splunk setup is largely based on syslog but because we want to have raw syslog files in addition to having them indexed by Splunk we allow syslog to write the logs to disk and then have Splunk watch the created files.  Some information such as facility and log level get lost during this process with most default syslog configurations.  To resolve this we did a little bit of reconfiguring to our syslog installs.First, it&#8217;s important to note that we actually use syslog-ng rather than vanilla syslog.  Syslog-ng has some handy options for templating output as of 1.5.3.  For each destination you can specify a template function:</p>
<p><code>
<pre>destination df_syslog { file("/var/log/syslog" template("$FULLDATE $FULLHOST $TAG $LEVEL $MESSAGE\n") template_escape(no)); };</pre>
<p></code></p>
<p>FULLDATE includes the year in the timestamp.  FULLHOST provides the hostname.  TAG is a hex encoding of the facility and level.  $LEVEL is a text representation of the level.  $MESSAGE is obviously just the message.  The template_escape(no) directive says that quotes should not be escaped.  Also note the newline at the end of the template.  Without it your output will be rather unreadable.</p>
<p>And for reference the default appears to be similar to:</p>
<p><code>
<pre>"$DATE $FULLHOST $MESSAGE\n" template_escape(no)</pre>
<p></code>
</li>
</ol>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F10%2F12%2Fspelunking-into-your-logs-with-splunk%2F&amp;title=Spelunking%20into%20your%20logs%20with%20Splunk" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F10%2F12%2Fspelunking-into-your-logs-with-splunk%2F&amp;title=Spelunking%20into%20your%20logs%20with%20Splunk&amp;bodytext=At%20Agora%20we%27re%20experimenting%20with%20Splunk%20as%20a%20error%20collection%20and%20reporting%20tool.%C2%A0%20The%20idea%20is%20that%20all%20our%20services%20will%20spit%20out%20error%20information%20to%20syslog%20which%20will%20be%20picked%20up%20and%20indexed%20by%20Splunk.%C2%A0%20Splunk%20will%20be%20configured%20to%20display%20inf" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F10%2F12%2Fspelunking-into-your-logs-with-splunk%2F&amp;title=Spelunking%20into%20your%20logs%20with%20Splunk&amp;notes=At%20Agora%20we%27re%20experimenting%20with%20Splunk%20as%20a%20error%20collection%20and%20reporting%20tool.%C2%A0%20The%20idea%20is%20that%20all%20our%20services%20will%20spit%20out%20error%20information%20to%20syslog%20which%20will%20be%20picked%20up%20and%20indexed%20by%20Splunk.%C2%A0%20Splunk%20will%20be%20configured%20to%20display%20inf" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2009%2F10%2F12%2Fspelunking-into-your-logs-with-splunk%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2009/10/12/spelunking-into-your-logs-with-splunk/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Advanced Page Caching Hacks in NGINX</title>
		<link>http://blog.agoragames.com/2009/06/26/advanced-page-caching-hacks-in-nginx/</link>
		<comments>http://blog.agoragames.com/2009/06/26/advanced-page-caching-hacks-in-nginx/#comments</comments>
		<pubDate>Fri, 26 Jun 2009 17:59:07 +0000</pubDate>
		<dc:creator>Jason LaPorte</dc:creator>
				<category><![CDATA[Bending Rails]]></category>
		<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[page caching]]></category>

		<guid isPermaLink="false">http://blog.agoragames.com/?p=308</guid>
		<description><![CDATA[Those of you in the Rails community who use NGINX may have come across this before: Ezra Zygmuntowicz&#8217;s NGINX config. It bears some similarity to the ones we use at Agora. Specifically, the section relating to serving page-cached files. The relevant lines (pulled from one of our configs) looks like this:
if (-f $request_filename.html) { rewrite [...]]]></description>
			<content:encoded><![CDATA[<p>Those of you in the Rails community who use NGINX may have come across <a href="http://brainspl.at/nginx.conf.txt" target="_blank">this</a> before: Ezra Zygmuntowicz&#8217;s NGINX config. It bears some similarity to the ones we use at Agora. Specifically, the section relating to serving page-cached files. The relevant lines (pulled from one of our configs) looks like this:</p>
<pre>if (-f $request_filename.html) { rewrite (.*) $1.html break; }
if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; }
if (!-f $request_filename) { proxy_pass http://some-proxy; }</pre>
<p>This generally works well, for simple cases. Unfortunately, we&#8217;ve run into some more complex ones where it didn&#8217;t cut it. I&#8217;ll outline two of those cases below and show what we did to fix it.</p>
<p><span id="more-308"></span></p>
<p>The first problem came up when we were page-caching both HTML and XML files (that is, there might be a <tt>slots/show/47.html</tt> and a <tt>slots/show/47.xml</tt>. (You can&#8217;t do this by default in Rails. We had to patch it.) The problem was that when you request <tt>/slots/show/47</tt>, the NGINX config only checks for and serves the HTML file, even when what you really wanted was XML. Of course, checking for the XML file gives the reverse problem: if you&#8217;re in a web browser, you get XML instead of pretty HTML. Not so hot.</p>
<p>My solution was to assume that the user wants XML unless their browser says otherwise (via the HTTP Accepts: header), in which case we check for HTML first instead. If we can&#8217;t find the relevant file, we try with the other extension (in case we guessed wrong), and finally we kick the request to the proxy if we can&#8217;t satisfy it. Thus, it looks like this:</p>
<pre># figure out the order we should search the cache
set $preferred_format xml;
set $secondary_format html;

if ($http_accept ~* text/html) {
  set $preferred_format html;
  set $secondary_format xml;
}

# check the cache for cached files
if (-f $request_filename.$preferred_format) {
  rewrite (.*) $1.$preferred_format break;
}

if (-f $request_filename/index.$preferred_format) {
  rewrite (.*) $1/index.$preferred_format break;
}

if (-f $request_filename.$secondary_format) {
  rewrite (.*) $1.$secondary_format break;
}

if (-f $request_filename/index.$secondary_format) {
  rewrite (.*) $1/index.$secondary_format break;
}

# if the file doesn't exist, let the application sort everything out
if (!-f $request_filename) { proxy_pass http://some-proxy; }</pre>
<p>The second case was a bit more subtle, but is similar in theory: one of our sites uses proper REST (that is, we support the HTTP GET, PUT, DELETE, etc. methods). When a user performed a GET request, the page gets cached; if they perform a DELETE sometime after that, NGINX (which is not configured to handle REST by default) simply returns the cached file happily instead of forwarding the DELETE request to the application. (As you can imagine, tracking down the source of this problem was not the easiest thing in the world.)</p>
<p>The solution in this case was to disable page caching for GET requests. Unfortunately, NGINX&#8217;s support for if statements isn&#8217;t so hot, so we had to do something fairly hacky to get it to work. (For the record, while I&#8217;ve not been enthused with the if statements, I tend to like NGINX in most other areas, so a couple silly warts like this are excusable for me.)</p>
<pre># Look for "/foo.zmog" unless we're asking for a GET request, in which case
# we look for "/foo.xml". Since "/foo.zmog" will never exist, this means
# that we will only check for pagecached files on a GET request. (Yes, this
# is totally ass-backwards. NGINX is awesome except in this case.)
set $cache_suffix "zmog";
if ($request_method = GET) {
  set $cache_suffix "xml";
}

# Caching rewrites
if (-f $request_filename.$cache_suffix) {
  rewrite (.*) $1.$cache_suffix break;
}

if (-f $request_filename/index.$cache_suffix) {
  rewrite (.*) $1/index.$cache_suffix break;
}

# More metrics logging for cached files
if (!-f $request_filename) { proxy_pass http://switchblade_proxy; }</pre>
<p>As you can see, sometimes, making NGINX play nice requires some lateral thinking, but you can generally always get it to do what you need to.</p>

<div class="sociable">

<ul>
	<li class="sociablefirst"><a rel="nofollow"  target="_blank" href="http://reddit.com/submit?url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F06%2F26%2Fadvanced-page-caching-hacks-in-nginx%2F&amp;title=Advanced%20Page%20Caching%20Hacks%20in%20NGINX" title="Reddit"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/reddit.png" title="Reddit" alt="Reddit" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F06%2F26%2Fadvanced-page-caching-hacks-in-nginx%2F&amp;title=Advanced%20Page%20Caching%20Hacks%20in%20NGINX&amp;bodytext=Those%20of%20you%20in%20the%20Rails%20community%20who%20use%20NGINX%20may%20have%20come%20across%20this%20before%3A%20Ezra%20Zygmuntowicz%27s%20NGINX%20config.%20It%20bears%20some%20similarity%20to%20the%20ones%20we%20use%20at%20Agora.%20Specifically%2C%20the%20section%20relating%20to%20serving%20page-cached%20files.%20The%20relevant%20" title="Digg"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a></li>
	<li><a rel="nofollow"  target="_blank" href="http://delicious.com/post?url=http%3A%2F%2Fblog.agoragames.com%2F2009%2F06%2F26%2Fadvanced-page-caching-hacks-in-nginx%2F&amp;title=Advanced%20Page%20Caching%20Hacks%20in%20NGINX&amp;notes=Those%20of%20you%20in%20the%20Rails%20community%20who%20use%20NGINX%20may%20have%20come%20across%20this%20before%3A%20Ezra%20Zygmuntowicz%27s%20NGINX%20config.%20It%20bears%20some%20similarity%20to%20the%20ones%20we%20use%20at%20Agora.%20Specifically%2C%20the%20section%20relating%20to%20serving%20page-cached%20files.%20The%20relevant%20" title="del.icio.us"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a></li>
	<li class="sociablelast"><a rel="nofollow"  target="_blank" href="http://technorati.com/faves?add=http%3A%2F%2Fblog.agoragames.com%2F2009%2F06%2F26%2Fadvanced-page-caching-hacks-in-nginx%2F" title="Technorati"><img src="http://blog.agoragames.com/wp-content/plugins/var/www/waxer-blog/shared/wp-content/plugins/sociable/images/technorati.png" title="Technorati" alt="Technorati" class="sociable-hovers" /></a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.agoragames.com/2009/06/26/advanced-page-caching-hacks-in-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->