<?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>Joe's Blog! &#187; Linux</title>
	<atom:link href="http://www.joeandmotorboat.com/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.joeandmotorboat.com</link>
	<description></description>
	<lastBuildDate>Fri, 08 Jan 2010 00:00:31 +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>Compiling Nginx with Syslog Support.</title>
		<link>http://www.joeandmotorboat.com/2009/09/08/compiling-nginx-with-syslog-support/</link>
		<comments>http://www.joeandmotorboat.com/2009/09/08/compiling-nginx-with-syslog-support/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 19:51:06 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=943</guid>
		<description><![CDATA[I recently setup a rsyslog server for my employer. Rsyslog is an enhanced syslog server that is multi-threaded. There is all sorts of filtering and rules that can be setup in the configuration. Cool stuff. In an effort to get as many systems using syslog as I can I needed to track down how to [...]]]></description>
			<content:encoded><![CDATA[<p>I recently setup a <a href="http://www.rsyslog.com/">rsyslog</a> server for <a href="http://cloudant.com/">my employer</a>. Rsyslog is an enhanced syslog server that is multi-threaded. There is all sorts of filtering and rules that can be setup in the configuration. Cool stuff. In an effort to get as many systems using syslog as I can I needed to track down how to get syslog support built into nginx as a couple of our backend systems use it. The first thing I found was the out of date patch on <a href="http://wiki.nginx.org/Nginx3rdPartyModules#Patches">this page</a> over at the nginx wiki. Unfortunately this doesn&#8217;t work for me as I already run 0.7.61. A quick email to the nginx mailing list and I found out about <a href="http://bugs.gentoo.org/attachment.cgi?id=197180">another patch set</a> for 0.7.x and 0.8.x by the same author as the old one. Basically it&#8217;s as easy as patching the nginx source with the aforementioned patch and then the standard ./configure, make and make install with one catch. You need to add <em>&#8211;with-syslog</em> to your configure. Unfortunately this didn&#8217;t seem to work for me I needed to also add the CFLAG to add syslog support in as well by running <em>export CFLAGS=&#8221;$CFLAGS -DUSE_SYSLOG&#8221;</em>. After that run your build and things should be ready to go. After the <em>make</em> if you want to double check that syslog support got built just run <em>strings objs/nginx | grep openlog</em> if you get &#8220;openlog&#8221; as a result you should be ready to rock.</p>
<p>Now for your rsyslog setup you may want to have nginx log to its own files rather than the default syslog log file. To do that just add the following to your configuration:<br />
<code><br />
if $programname == 'nginx' and $syslogseverity <= '4' then /var/log/nginx_error.log<br />
if $programname == 'nginx' and $syslogseverity == '5' then /var/log/nginx_access.log<br />
if $programname == 'nginx' and $syslogseverity >= '6' then /var/log/nginx_debug_info.log<br />
</code></p>
<p>This will filter out all the logs for nginx by the severity of the log message. I have all errors go to one (<= 4), access logs (== 5) go to another and debug and info messages (>= 6) go to the last.</p>
<p>For more details on configuring rsyslog check out the <a href="http://wiki.rsyslog.com/index.php/Main_Page">wiki</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/09/08/compiling-nginx-with-syslog-support/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HAProxy Stats Socket and fun with socat.</title>
		<link>http://www.joeandmotorboat.com/2009/08/20/haproxy-stats-socket-and-fun-with-socat/</link>
		<comments>http://www.joeandmotorboat.com/2009/08/20/haproxy-stats-socket-and-fun-with-socat/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 22:22:40 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=935</guid>
		<description><![CDATA[I&#8217;ve been debugging issues with HTTP, my backend servers and HAProxy. After a quick email to the HAProxy mailing list I found out about a configuration option stats socket PATH. This will create a socket you can send commands to and get more information out of HAProxy. To do this I just used some simle [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been debugging issues with HTTP, my backend servers and HAProxy. After a quick email to the HAProxy mailing list I found out about a configuration option <em>stats socket PATH</em>. This will create a socket you can send commands to and get more information out of HAProxy. To do this I just used some simle unix tools, the key is <a href="http://www.dest-unreach.org/socat/">socat</a>. From the man:</p>
<blockquote><p>
socat is a relay for bidirectional data transfer between two independent data channels. Each of these data channels may be a file, pipe, device (serial line etc. or a pseudo terminal), a socket (UNIX, IP4, IP6 &#8211; raw, UDP, TCP), an SSL socket, proxy CONNECT connection, a file descriptor (stdin etc.), the GNU line editor (readline), a program, or a combination of two of these. These modes include generation of &#8220;listening&#8221; sockets, named pipes, and pseudo terminals.
</p></blockquote>
<p>Here are a few examples of how to use the stats socket. First, you need to add <em>stats socket PATH</em> to your configuration and restart haproxy. You should then find a socket located at the path specified, I used <em>/tmp/haproxy</em>. Now you can send it commands to get more information and stats from HAProxy.<br />
<code><br />
echo "show stat" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p>This will give you stats on all of your backends and frontends, some of the same stuff you see on the stats page enabled by the <em>stats uri</em> configuration. As an added bonus it&#8217;s all in CSV.<br />
<code><br />
echo "show errors" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p><em>show errors</em> will give you a capture of last error on each backend/frontend.<br />
<code><br />
echo "show info" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p>This will give you information about the running HAProxy process such as pid, uptime and etc.<br />
<code><br />
echo "show sess" | socat unix-connect:/tmp/haproxy stdio<br />
</code></p>
<p>This will dump (possibly huge) info about all know sessions.</p>
<p>For more details check out <a href="http://haproxy.1wt.eu/download/1.3/doc/configuration.txt">the docs</a> section 9 and <em>stats socket</em> in section 3.1.</p>
<p><strong>Bonus socat fun.</strong></p>
<p>socat is a more full featured cousin of <a href="http://netcat.sourceforge.net/">netcat</a>. Both can be used in similar ways, one thing I use them for occasionally is debugging REST and etc. This was a real help when working with an API that didn&#8217;t have a library, I could test things out without needing to make erroneous calls to the API. In the simplest case you can have either of them listen on a port and output all the details of the request. To do this with socat run:</p>
<p><code>socat tcp-listen:8000 stdio</code></p>
<p>This will listen for connections on port 8000. Doing the same thing with netcat is easy as well:</p>
<p><code>netcat -l -p 8000</code></p>
<p>For instance you can see the output from creating a document in CouchDB.</p>
<p>In one terminal:<br />
<code><br />
$ irb<br />
irb(main):001:0> require 'rubygems'<br />
=> true<br />
irb(main):002:0> require 'rest_client'<br />
=> true<br />
irb(main):003:0> RestClient.put("http://localhost:8000/somedb/somedoc", "{\"somekey\": \"somevalue\"}", :content_type => "application/json")<br />
</code></p>
<p>In another run your mock server:<br />
<code><br />
$ socat tcp-listen:8000 stdio<br />
PUT /somedb/somedoc HTTP/1.1<br />
Accept: application/xml<br />
Content-Type: application/json<br />
Accept-Encoding: gzip, deflate<br />
Content-Length: 24<br />
Host: localhost:8000</p>
<p>{"somekey": "somevalue"}<br />
</code></p>
<p>Oh! By the way, if you install netcat from source, don&#8217;t compile with <em>-DGAPING_SECURITY_HOLE</em> unless you know what you are doing. <img src='http://www.joeandmotorboat.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/08/20/haproxy-stats-socket-and-fun-with-socat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Boston Meet-up.</title>
		<link>http://www.joeandmotorboat.com/2009/07/21/boston-meet-up/</link>
		<comments>http://www.joeandmotorboat.com/2009/07/21/boston-meet-up/#comments</comments>
		<pubDate>Tue, 21 Jul 2009 17:01:25 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=929</guid>
		<description><![CDATA[Headed to Boston next week, planning to meet-up next Tuesday (7/28) 7pm at Cambridge Brewing Co. Drop by for a beer, food and maybe a little Erlang.
]]></description>
			<content:encoded><![CDATA[<p>Headed to Boston next week, planning to meet-up next Tuesday (7/28) 7pm at <a href="http://www.cambrew.com/">Cambridge Brewing Co</a>. Drop by for a beer, food and maybe a little Erlang.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/07/21/boston-meet-up/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing haproxy_join, and how to use it with Chef.</title>
		<link>http://www.joeandmotorboat.com/2009/07/01/introducing-haproxy_join-and-how-to-use-it-with-chef/</link>
		<comments>http://www.joeandmotorboat.com/2009/07/01/introducing-haproxy_join-and-how-to-use-it-with-chef/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 21:24:01 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=923</guid>
		<description><![CDATA[Inspired by Holger Just&#8217;s haproxy configuration tool I decided to write one my own that worked better for my setup and haproxy_join was born. It&#8217;s a simple Ruby script that allows you to break up a monolithic haproxy configuration file in to pieces.
haproxy_join expects files and directories to be in the following scheme:

HAPROXY_PATH/conf/global.cfg (file)
HAPROXY_PATH/conf/defaults.cfg (file)
HAPROXY_PATH/conf/frontend.cfg [...]]]></description>
			<content:encoded><![CDATA[<p>Inspired by <a href="http://github.com/finnlabs/haproxy/tree/master">Holger Just&#8217;s haproxy configuration tool</a> I decided to write one my own that worked better for my setup and <a href="http://github.com/joewilliams/haproxy_join/tree/master">haproxy_join</a> was born. It&#8217;s a simple Ruby script that allows you to break up a monolithic haproxy configuration file in to pieces.</p>
<p>haproxy_join expects files and directories to be in the following scheme:<br />
<code><br />
HAPROXY_PATH/conf/global.cfg (file)<br />
HAPROXY_PATH/conf/defaults.cfg (file)<br />
HAPROXY_PATH/conf/frontend.cfg (file)<br />
HAPROXY_PATH/conf/frontend.d (dir of frontend configs)<br />
HAPROXY_PATH/conf/backend.d (dir backend configs)<br />
</code></p>
<p>The HAPROXY_PATH and resulting configuration file are specified when running the haproxy_join command. On most systems it would look like the following, all you need to do is break up your current config and put it in the above structure.<br />
<code><br />
haproxy_join haproxy.cfg /etc/haproxy/<br />
</code></p>
<p>haproxy_join will also attempt to backup your configuration file before writing a new one.</p>
<p>This works great in tandem with a tool like <a href="http://wiki.opscode.com/display/chef/Home">Chef</a>, allowing you to have Chef manage each small configuration file with a template and haproxy_join to concatenate them together each time they are changed. You can achieve this by using a Chef recipe based on the default opscode haproxy recipe and a slightly modified haproxy init script based on Holger Just&#8217;s haproxy init script. The recipe will notify haproxy Chef to restart haproxy if a configuration has changed and the init script will run haproxy_join before it restarts haproxy. I have posted an example of the <a href="http://gist.github.com/139042">cookbook recipe</a> and the <a href="http://gist.github.com/139064">init script</a>. Neither of these have been heavily used/tested so try them out before you put them into production.</p>
<p>Hope this helps anyone with large haproxy configurations. Let me know if you have any questions in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/07/01/introducing-haproxy_join-and-how-to-use-it-with-chef/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Claws Mail.</title>
		<link>http://www.joeandmotorboat.com/2009/05/30/claws-mail/</link>
		<comments>http://www.joeandmotorboat.com/2009/05/30/claws-mail/#comments</comments>
		<pubDate>Sat, 30 May 2009 18:49:12 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=904</guid>
		<description><![CDATA[I recently switched to using Claws Mail from Mozilla Thunderbird. This was mostly to try something new and because of the seeming stagnation of the Thunderbird project. So far so good, here are a couple things that I think are cool.
Lots of plugins and themes. Claws Mail has for all sorts of tasks and features. [...]]]></description>
			<content:encoded><![CDATA[<p>I recently switched to using <a href="http://www.claws-mail.org/">Claws Mail</a> from <a href="http://www.mozillamessaging.com/en-US/thunderbird/">Mozilla Thunderbird</a>. This was mostly to try something new and because of the seeming stagnation of the Thunderbird project. So far so good, here are a couple things that I think are cool.</p>
<p>Lots of <a href="http://www.claws-mail.org/plugins.php?section=downloads">plugins</a> and <a href="http://www.claws-mail.org/themes.php?section=downloads">themes</a>. Claws Mail has for all sorts of tasks and features. The ones that I think are key are GTKHTML, Notification (libnotify/notify-osd) and SpamAssassin. SpamAssassin in interesting because it actually uses a full SpamAssassin installation like you would see on a mail server. The plugin connects to the spamd daemon running on your system and you can teach it what is spam and ham. If you are running Ubuntu all/most of the plugins are available in the normal repositories.</p>
<p><img src="http://joeandmotorboat.com/images/plugins.png" alt="claws plugins" /></p>
<p>Also very cool is its auto-generated mail filters. Basically you can right click any email and create a filter based on the headers. This worked great for all the mailing lists and ticketing systems I use.</p>
<p><img src="http://joeandmotorboat.com/images/filter.png" alt="claws filter" width="495" height="539" /></p>
<p>Claws also has a network log which worked great for diagnosing issues with an IMAP or SMTP session.</p>
<p><img src="http://joeandmotorboat.com/images/log.png" alt="claws net log" width="539" height="390" /></p>
<p>There are a few quirks, the first that I noticed was that when Claws is checking the mail servers for new mail it locks out some of the menu items. This is annoying if an automatic check happens when you are trying to change a config item. Another annoyance is when using the up and down keys to go through messages you either have to click on the message or hit enter to view it. It would be nice if they loaded as soon as you arrowed to it. Lastly, the interface seems a little less polished than Thunderbird but that may be just because I am more accustomed to TBird after years of use.</p>
<p>If you are interested in trying Claws out and use Ubuntu I recommend adding the <a href="https://launchpad.net/~claws-mail/+archive/ppa">Claws PPA</a> to your apt sources to get the latest version and claws-mail-extra-plugins.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/05/30/claws-mail/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>CouchDB Load Balancing and Replication using HAProxy.</title>
		<link>http://www.joeandmotorboat.com/2009/01/27/couchdb-load-balancing-and-replication-using-haproxy/</link>
		<comments>http://www.joeandmotorboat.com/2009/01/27/couchdb-load-balancing-and-replication-using-haproxy/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 17:01:32 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=820</guid>
		<description><![CDATA[Last night, I decided to dig into CouchDB a bit more than I have in the past and setup a simple load balanced and replicated setup using HAProxy. In the end it was a pretty easy feat and seems to work fairly well. Here&#8217;s what I had to do.
First, I setup three instances of CouchDB [...]]]></description>
			<content:encoded><![CDATA[<p>Last night, I decided to dig into <a href="http://couchdb.apache.org/">CouchDB</a> a bit more than I have in the past and setup a simple load balanced and replicated setup using <a href="http://haproxy.1wt.eu/">HAProxy</a>. In the end it was a pretty easy feat and seems to work fairly well. Here&#8217;s what I had to do.</p>
<p>First, I setup three instances of CouchDB on the same machine using different configuration files, PIDs and loopback addresses for each. This can certainly be exchanged for three different machines. Running them on the same machine make sure you adjust the DbRootDir, BindAddress, LogFile in the configuration file and use a command like the following to start things up. This will make sure the non-default configuration and PID location are used.</p>
<blockquote><p>
./couchdb -c SOME_PATH/couchdb2.ini -p SOME_PATH/couchdb2.pid
</p></blockquote>
<p>As you may already know CouchDB has a nice web interface called futon, http://HOSTNAME:5984/_utils/  Using futon I created a database with the same name on all three. I then chose which instance would be my &#8220;master&#8221;, couchdb1 and couchdb2 and 3 will be &#8220;slaves&#8221;. I put master and slave in quotes because there isn&#8217;t this type of relationship in CouchDB as far as I can tell. All instances can replicate to each other as long as they can connect to each other, so master-slave replication is simply the type of configuration I am enforcing with HAProxy and my replication POST commands. More on these bits later. I then created created a document on my master node and using futon&#8217;s replicator replicated the changes to the other nodes. I then wanted to find a way to automate or schedule this. You can <a href="http://wiki.apache.org/couchdb/Frequently_asked_questions#how_replication">initiate replication simply by sending a POST request</a> to couchdb so I wrote a simple curl script to do just that.</p>
<p>First I created the replication POST body in a file:</p>
<blockquote><p>
{&#8220;source&#8221;:&#8221;test_rep&#8221;,&#8221;target&#8221;:&#8221;http://couchdb2:5984/test_rep&#8221;}
</p></blockquote>
<p>When run against the master this will replicate the master to couchdb2. I wrote a similar file for couchdb3 as well.</p>
<p>Then using curl I can send this body to the master:</p>
<blockquote><p>
curl -X POST &#8211;data @couchdb1_2_rep http://couchdb1:5984/_replicate<br />
curl -X POST &#8211;data @couchdb1_3_rep http://couchdb1:5984/_replicate
</p></blockquote>
<p>After running you should see some output that starts with <em>{&#8220;ok&#8221;:true,&#8221;session_id &#8230;}</em> this means things went well. You should also see some output in the logs on both instances. These commands can be put in a cron to run a specific intervals to keep the slaves updated. You can also create a script and configure <a href="http://wiki.apache.org/couchdb/Regenerating_views_on_update?action=show&#038;redirect=RegeneratingViewsOnUpdate">DbUpdateNotificationProcess</a> to replicate after each update. The later is probably a nicer solution but a cron and curl should get you started.</p>
<p>I then moved on to setting up HAProxy to load balance between the nodes. Since I wanted a master-slave relationship between the nodes I needed to set HAProxy to only send POSTs, PUTs and DELETEs to the master and GET requests to the two slaves. After checking the <a href="http://haproxy.1wt.eu/download/1.3/doc/haproxy-en.txt">docs</a> and playing with a couple different ACL configurations I didn&#8217;t find a solution. I then contacted the mailing list for some advice and conveniently a solution was sent back to me quickly. They also told me about another piece of <a href="http://haproxy.1wt.eu/download/1.3/doc/configuration.txt">documentation</a> I didn&#8217;t find initially. My configuration for HAProxy is pretty basic but it shows what needs to be done.</p>
<blockquote><p>
global<br />
	maxconn 4096<br />
	nbproc 2</p>
<p>defaults<br />
	mode http<br />
	clitimeout 150000<br />
	srvtimeout  30000<br />
	contimeout  4000<br />
    balance roundrobin<br />
    stats enable<br />
    stats uri /haproxy?stats</p>
<p>frontend couchdb_lb<br />
	bind localhost:8080</p>
<p>	acl master_methods method POST DELETE PUT<br />
	use_backend master_backend if master_methods<br />
	default_backend slave_backend</p>
<p>backend master_backend<br />
	server couchdb1 couchdb1:5984 weight 1 maxconn 512 check</p>
<p>backend slave_backend<br />
	server couchdb2 couchdb2:5984 weight 1 maxconn 512 check<br />
	server couchdb3 couchdb3:5984 weight 1 maxconn 512 check</p>
</blockquote>
<p>The part that enforces where the PUTs, DELETEs and POSTs go is the ACL definition and it basically says that if HAProxy receives a POST, DELETE or PUT then use the master node otherwise use a slave. </p>
<p>Once done I started up HAProxy and tested it out and found that it worked out nicely with GETs going to the slaves in roundrobin fashion and PUTs, DELETEs and POSTs going to the master. I then made a slight change to my curl command from earlier to have the replication POSTs go through HAProxy just to make sure.</p>
<blockquote><p>
curl -X POST &#8211;data @couchdb1_2_rep http://localhost:8080/_replicate<br />
curl -X POST &#8211;data @couchdb1_3_rep http://localhost:8080/_replicate
</p></blockquote>
<p>If things are working properly you should find that the replication POST commands only go to the master node and the GET commands got to the two slaves.</p>
<p>CouchDB is pretty easy to get going and fun to work with. Hopefully this will help you get going.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/01/27/couchdb-load-balancing-and-replication-using-haproxy/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Nginx vs Yaws vs MochiWeb : Web Server Performance Deathmatch, Part 2 [Update x 2]</title>
		<link>http://www.joeandmotorboat.com/2009/01/03/nginx-vs-yaws-vs-mochiweb-web-server-performance-deathmatch-part-2/</link>
		<comments>http://www.joeandmotorboat.com/2009/01/03/nginx-vs-yaws-vs-mochiweb-web-server-performance-deathmatch-part-2/#comments</comments>
		<pubDate>Sat, 03 Jan 2009 23:19:33 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=742</guid>
		<description><![CDATA[Update 1: Retest data (using different machine and Erlang kernel polling) added near bottom of post.
Update 2: More details and testing on the weird MochiWeb kernel polling results, bottom of post.
Almost a year ago I did some Apache and Nginx performance testing. Apparently I have the bug again and have done some performance testing on [...]]]></description>
			<content:encoded><![CDATA[<p><em>Update 1: Retest data (using different machine and Erlang kernel polling) added near bottom of post.</em></p>
<p><em>Update 2: More details and testing on the weird MochiWeb kernel polling results, bottom of post.</em></p>
<p>Almost a year ago I did some <a href="http://www.joeandmotorboat.com/2008/02/28/apache-vs-nginx-web-server-performance-deathmatch/">Apache and Nginx performance testing</a>. Apparently I have the bug again and have done some performance testing on <a href="http://www.nginx.net/">Nginx</a>, <a href="http://yaws.hyber.org/">Yaws</a> and <a href="http://code.google.com/p/mochiweb/">MochiWeb</a>. The latter two being Erlang based. Again deathmatch may be an overstatement but this is my attempt at gleaning some interesting performance data from some high performance web servers. Also, I attempted to improve the graphs this time around since they were a bit hard to read the last time.</p>
<p><strong>The Setup:</strong></p>
<p>I was not able to use the same server and setup as the last time, so comparing between this and my last deathmatch probably isn&#8217;t very accurate. For this test I used a Intel Dual Core 2.2GHz, 4GB RAM machine running Ubuntu 8.10 (64bit) and for the test server. Erlang (R12B-3), Yaws (1.77) and Nginx (0.6.32) are installed from the standard repository and mochiweb from subversion (rev 88). All are using the <strong>default configurations</strong> outside of adjusting listening port numbers. The test is again against a basic robots.txt file. The tests were done using a consumer grade 100mb switch and all tests originated from an old laptop I had laying around. I think that about covers the test bed, if you have any questions let me know.</p>
<p>For the tests I used autobench (httperf under the hood) with the following command, each test ran ten minutes apart. The order of the tests were done in was MochiWeb then Yaws and lastly Nginx.</p>
<blockquote><p>autobench &#8211;single_host &#8211;host1 HOST &#8211;port1 PORT &#8211;uri1 /robots.txt &#8211;low_rate 10 &#8211;high_rate 200 &#8211;rate_step 10 &#8211;num_call 10 &#8211;num_conn 5000 &#8211;timeout 5 &#8211;file SERVER-results-`date +%F-%H:%M:%S`.tsv</p></blockquote>
<p><strong>The Results:</strong></p>
<p>There are a few results from httperf/autobench that I would like to show, errors, network I/O, reply rate (and it&#8217;s standard deviation) and response time. <em>(click on the graphs for a larger view)</em></p>
<p><a href="http://www.joeandmotorboat.com/files/errors.png"><img src="http://www.joeandmotorboat.com/files/errors.png" alt="nginx yaws mochiweb errors" width="514" height="387" /></a></p>
<p>MochiWeb and Yaws both seem to be the most consistent here. Nginx had a couple of funky spikes, I do not know if this was an issue with Nginx or with my tests and/or test bed. Take from it what you will.</p>
<p><a href="http://www.joeandmotorboat.com/files/network.png"><img src="http://www.joeandmotorboat.com/files/network.png" alt="mochiweb yaws nginx network io" width="514" height="387" /></a></p>
<p>Nginx seems to use a bit more network I/O consistently through the lower ranges of this test and then again as some spikes. MochiWeb and Yaws seem to have some inconsistencies as well.</p>
<p><a href="http://www.joeandmotorboat.com/files/replyrate.png"><img src="http://www.joeandmotorboat.com/files/replyrate.png" alt="mochiweb yaws nginx reply rate" width="514" height="387" /></a></p>
<p>The reply rate and network I/O graphs certainly seem to be tied, which would make sense. <em>Edit: Average reply rate is average replies per second.</em></p>
<p><a href="http://www.joeandmotorboat.com/files/replyratestddev.png"><img src="http://www.joeandmotorboat.com/files/replyratestddev.png" alt="mochiweb yaws nginx reply rate standard deviation" width="514" height="387" /></a></p>
<p>In the higher reaches of the tests Yaws seems to be most consistent.</p>
<p><a href="http://www.joeandmotorboat.com/files/responsetime.png"><img src="http://www.joeandmotorboat.com/files/responsetime.png" alt="mochiweb yaws nginx response time" width="514" height="387" /></a></p>
<p>MochiWeb seems to have consistently the highest response times with Nginx has the lowest. This also follows the data from the first deathmatch. Nginx had consistently low response times against Apache. <em>Edit: Response time is how quickly replies are sent in milliseconds.</em></p>
<p>Next up are the system graphs, I have CPU usage (both cores combined), context switches, interrupts and load. To help read these please note recall that each test ran ten minutes apart and the order of the tests was MochiWeb then Yaws and lastly Nginx. The data was gathered using sar at five minute intervals and graphed using ksar.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_all-cpu.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_all-cpu.png" alt="nginx yaws mochiweb cpu usage" width="514" height="387" /></a></p>
<p>It seems Nginx is the clear winner here. Kernel polling may be the answer here, a retest may be in order to see if it makes a difference.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_LinuxcswchSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_LinuxcswchSar.png" alt="nginx yaws mochiweb context switch" width="514" height="387" /></a></p>
<p>MochiWeb and Nginx seem pretty even on context switches with Yaws a little higher. I suppose turning on kernel polling might make this a bit more even, since Erlang and Nginx both use epoll. This may also account for the CPU usage difference above.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_LinuxintrSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_LinuxintrSar.png" alt="nginx yaws mochiweb interrupts" width="514" height="387" /></a></p>
<p>Interrupts are fairly even across all of them.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_LinuxloadSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws_LinuxloadSar.png" alt="nginx yaws mochiweb load" width="514" height="387" /></a></p>
<p>Again Nginx takes it, again likely due to kernel polling being disabled. That&#8217;s my best guess anywho.</p>
<p>The data I used to create the graphs and etc is available <a href="http://www.joeandmotorboat.com/files/webservertests_results.tar.gz">here</a>. </p>
<p>Let me know if you are interested in me retesting anything, I may try to enable kernel polling and try again if I get a chance.</p>
<p>Note that these are *my* experiences with each webserver, your testing and experiences may be different. As with most things there are pro&#8217;s, con&#8217;s, trade offs and pitfalls. The only way to find out what will work best for your environment is to test, test and test. </p>
<p><strong>Update</strong>: </p>
<p>I performed the upper half of the tests again to see if there were any changes to sporadic jumps in the graphs http performance graphs. My initial test using the old laptop I saw the same results. I then ran the tests from a VM (running Ubuntu 8.10 in a KVM VM) on my dual core machine and found that the results were much more even. Unfortunately it&#8217;s the same machine that the webservers are running on but the results look much better. The first set is using the same setup as before but just adjusted to have the top half test. The second is the same test but with kernel polling turned on in Erlang.</p>
<p><a href="http://www.joeandmotorboat.com/files/avgreplyrate-test2.png"><img src="http://www.joeandmotorboat.com/files/avgreplyrate-test2.png" alt="nginx yaws mochiweb reply rate" width="514" height="387" /></a></p>
<p>All of them are very even and close, no real winners here.</p>
<p><a href="http://www.joeandmotorboat.com/files/responsetime-test2.png"><img src="http://www.joeandmotorboat.com/files/responsetime-test2.png" alt="nginx yaws mochiweb response time" width="514" height="387" /></a></p>
<p>Looks like Nginx is the clear winner with Yaws next, followed by MochiWeb.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-test2_all-cpu.png"><img src="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-test2_all-cpu.png" alt="nginx yaws mochiweb cpu usage" width="514" height="387" /></a></p>
<p>Pretty much the same as last time (likely a little higher across the board due to running the tests in a VM on the same machine). Note that Nginx is a system process, so for Yaws and MochiWeb follow the blue line and Nginx follow the green. </p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-test2_LinuxcswchSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-test2_LinuxcswchSar.png" alt="nginx yaws mochiweb context switches" width="514" height="387" /></a></p>
<p>About the same as before, other than being higher due to running a VM.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-test2_LinuxloadSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-test2_LinuxloadSar.png" alt="nginx yaws mochiweb load" width="514" height="387" /></a></p>
<p>Pretty much the same as before again, Nginx seems the lowest.</p>
<p>Now for the tests <strong>with kernel polling enabled in Erlang</strong> (<em>erl +K true</em>).</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-replyrate-wkernelpolling.png"><img src="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-replyrate-wkernelpolling.png" alt="nginx yaws mochiweb reply rate kernel polling" width="514" height="387" /></a></p>
<p>With kernel polling on it looks like Yaws actually performs better in the reply rate test with MochiWeb performing worse and Nginx in the middle</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-responsetime-wkernelpolling.png"><img src="http://www.joeandmotorboat.com/files/nginx-yaws-mochiweb-responsetime-wkernelpolling.png" alt="nginx yaws mochiweb response time kernel polling" width="514" height="387" /></a></p>
<p>In the response time test a huge change is noted, MochiWeb goes from roughly a ~14 ms response time at 2000 requests to ~65 ms. Also noted Yaws performs much better matching or beating Nginx.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws-wkernelpolling_all-cpu.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws-wkernelpolling_all-cpu.png" alt="nginx yaws mochiweb cpu usage kernel polling" width="514" height="387" /></a></p>
<p>With kernel polling in the Erlang webservers Nginx still seems to come out on top for CPU usage.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws-wkernelpolling_LinuxcswchSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws-wkernelpolling_LinuxcswchSar.png" alt="nginx yaws mochiweb context switches kernel polling" width="514" height="387" /></a></p>
<p>Following the performance trend we saw above Yaws sees a drop in context switches and MochiWeb increases.</p>
<p><a href="http://www.joeandmotorboat.com/files/nginx-mochi-yaws-wkernelpolling_LinuxloadSar.png"><img src="http://www.joeandmotorboat.com/files/nginx-mochi-yaws-wkernelpolling_LinuxloadSar.png" alt="nginx yaws mochiweb load kernel polling" width="514" height="387" /></a></p>
<p>Load-wise things stay roughly the same with Nginx being the lowest.</p>
<p>While it certainly seems that my old laptop that I did the original tests on is too slow or has a network issue, hopefully with these new tests we have some more clarity. It seems that Yaws improves with kernel polling enabled and competes well with Nginx. MochiWeb on the other hand apparently has issues with kernel polling and actually degrades performance. If anyone has more info on the internals of MochiWeb and possible causes I would be certainly interested.</p>
<p>If anyone would like the data from the second round of tests it is available <a href="http://www.joeandmotorboat.com/files/webservertests.3.tar.gz">here</a>.</p>
<p><strong>Update 2:</strong></p>
<p>I did some more testing to see what the issue might be with MochiWeb, response times and kernel polling. I did a few tests with different versions of Erlang, with and without kernel polling and testing from within and outside a KVM VM. From what I can tell the issue seems to be isolated to testing from within a VM with MochiWeb and kernel polling. Seems to be sorta strange but all my testing and retesting shows the same issue. Just to be clear on my setup, I am running httperf from with in a VM to MochiWeb running outside the VM. Here is the latest round of testing to show this point.</p>
<p><a href="http://www.joeandmotorboat.com/files/mochiweb-responsetime-kvm-kp.png"><img src="http://www.joeandmotorboat.com/files/mochiweb-responsetime-kvm-kp.png" alt="nginx yaws mochiweb kvm vm response time kernel polling" width="514" height="387" /></a></p>
<p>Even though the numbers are higher from within the VM without kernel polling, it certainly seems to be an issue with the combination of MochiWeb, KVM and kernel polling. Since I did not see the same spike from within a VM in the earlier tests with Yaws and kernel polling I assume it is not an issue with Erlang or it&#8217;s kernel polling mechanism conflicting with KVM. I am not entirely sure what to make of this other than MochiWeb, kernel polling and KVM don&#8217;t play well together and that <strong>kernel polling actually helps MochiWeb significantly when KVM is not involved</strong>. If anyone has any ideas on why that may be I am all ears.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2009/01/03/nginx-vs-yaws-vs-mochiweb-web-server-performance-deathmatch-part-2/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>SSH and Ruby</title>
		<link>http://www.joeandmotorboat.com/2008/10/13/ssh-and-ruby/</link>
		<comments>http://www.joeandmotorboat.com/2008/10/13/ssh-and-ruby/#comments</comments>
		<pubDate>Tue, 14 Oct 2008 02:10:02 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=671</guid>
		<description><![CDATA[The last couple days I have been a bit distracted from the Erlang stuff I have been doing lately and ended up some how playing with Ruby and the SSH library. For running commands on a bunch of machines at once it would work really well. Here&#8217;s some code I wrote and paraphrased from various [...]]]></description>
			<content:encoded><![CDATA[<p>The last couple days I have been a bit distracted from the Erlang stuff I have been doing lately and ended up some how playing with Ruby and the SSH library. For running commands on a bunch of machines at once it would work really well. Here&#8217;s some code I wrote and paraphrased from various sources.</p>
<blockquote><p>require &#8216;rubygems&#8217;<br />
require &#8216;net/ssh&#8217;</p>
<p>username=&#8221;yourusername&#8221;<br />
hostnames=["node01","node02"]<br />
script=&#8221;date;uptime;&#8221;</p>
<p>hostnames.each {|hostname|<br />
Net::SSH.start( hostname, username ) do |session|<br />
session.open_channel do |channel|<br />
channel.on_data { |chan,output| puts &#8220;#{output.inspect}&#8221; }<br />
channel.on_extended_data { |chan,type,output| print output }<br />
channel.exec script<br />
end<br />
session.loop<br />
end<br />
}</p></blockquote>
<p>This will run the commands contained in the <em>script</em> variable on the hosts in the hostnames array as the specified user. As it is currently it does not supply a password, so you&#8217;ll need keys setup. Adding your password is pretty simple, just check out the API <a href="http://net-ssh.rubyforge.org/ssh/v2/api/index.html">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2008/10/13/ssh-and-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu Ibex Alpha 6 Intel GigE Adapter Bug.</title>
		<link>http://www.joeandmotorboat.com/2008/09/24/ubuntu-ibex-alpha-6-intel-gige-adapter-bug/</link>
		<comments>http://www.joeandmotorboat.com/2008/09/24/ubuntu-ibex-alpha-6-intel-gige-adapter-bug/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 21:14:45 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=634</guid>
		<description><![CDATA[Don&#8217;t use the latest Ibex Alpha 6 if you run an Intel Gigabit ethernet card, there is a bug (here too) currently that will screw with the firmware render it inoperable by making the checksum fail. This applies to the e1000e driver but can cause issues if you have used e1000 in the past. The [...]]]></description>
			<content:encoded><![CDATA[<p>Don&#8217;t use the latest Ibex Alpha 6 if you run an Intel Gigabit ethernet card, there is a <a href="https://bugs.launchpad.net/ubuntu/+bug/267952">bug</a> (<a href="https://bugs.launchpad.net/ubuntu/+bug/272630">here too</a>) currently that will screw with the firmware render it inoperable by making the checksum fail. This applies to the e1000e driver but can cause issues if you have used e1000 in the past. The image download page says:</p>
<blockquote><p>Due to an unresolved bug in the Linux kernel included in these images, they should not be used on Intel ethernet hardware supported by the e1000e driver (Intel GigE). Doing so may render your network hardware permanently inoperable.</p>
<p>Older Intel ethernet hardware which uses the e1000 driver is not affected by this; however, some hardware which used the e1000 driver in previous Ubuntu releases, such as hardware that uses a PCI Express bus, has been moved from e1000 to e1000e in the latest kernel releases. If in doubt, do not use these images, and subscribe to https://bugs.launchpad.net/ubuntu/+source/linux/+bug/263555 to be notified when the bug is fixed.</p></blockquote>
<p>Yikes! Hope they have it fixed by the 10th.</p>
<p><em>Update: More info can be found in a <a href="http://kerneltrap.org/mailarchive/linux-kernel/2008/9/29/3450874/thread#mid-3450874">discussion</a> on the kernel mailing list.</em></p>
<p><em>Update #2: Looks like the main bug report is <a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/263555">here</a>. Looks like they are getting close to a resolution.</em></p>
<p><em>Update #3: Seems that a fix as been released and the final release of Ibex (8.10) will be out Oct 30th.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2008/09/24/ubuntu-ibex-alpha-6-intel-gige-adapter-bug/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Disco.</title>
		<link>http://www.joeandmotorboat.com/2008/09/08/disco/</link>
		<comments>http://www.joeandmotorboat.com/2008/09/08/disco/#comments</comments>
		<pubDate>Mon, 08 Sep 2008 13:05:19 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Clustering]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.joeandmotorboat.com/?p=610</guid>
		<description><![CDATA[Something I happened to see over here this weekend was Disco. It is a Map/Reduce framework written in Erlang. A user/implementer doesn&#8217;t need to know a lick of Erlang to get rolling but according to their site most folks use Python to write the actual jobs. If you as me a Map/Reduce framework built using [...]]]></description>
			<content:encoded><![CDATA[<p>Something I happened to see <a href="http://debasishg.blogspot.com/2008/09/more-erlang-with-disco.html">over here</a> this weekend was <a href="http://discoproject.org/">Disco</a>. It is a Map/Reduce framework written in Erlang. A user/implementer doesn&#8217;t need to know a lick of Erlang to get rolling but according to their site most folks use Python to write the actual jobs. If you as me a Map/Reduce framework built using Erlang makes a great amount of sense due to its message passing and light weight processes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.joeandmotorboat.com/2008/09/08/disco/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
