<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>igvita.com</title>
	
	<link>http://www.igvita.com</link>
	<description>A goal is a dream with a deadline.</description>
	<pubDate>Mon, 14 Jul 2008 15:45:51 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/igvita" type="application/rss+xml" /><feedburner:emailServiceId>532799</feedburner:emailServiceId><feedburner:feedburnerHostname>http://www.feedburner.com</feedburner:feedburnerHostname><item>
		<title>Fighting Technological Indulgences</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/335197349/</link>
		<comments>http://www.igvita.com/2008/07/14/fighting-technological-indulgences/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 15:45:51 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Agile Methods]]></category>

		<category><![CDATA[management]]></category>

		<category><![CDATA[startup]]></category>

		<guid isPermaLink="false">http://www.igvita.com/?p=186</guid>
		<description><![CDATA[That’s a nice one! Wonder if I should use Ruby, Python, or maybe even Perl to build it? As gearheads we tend to jump to the technical details with little afterthought, but should you even be building that feature in the first place? How do you make that call?
Whether you're a one man team with [...]]]></description>
			<content:encoded><![CDATA[<p>That’s a nice one! Wonder if I should use Ruby, Python, or maybe even Perl to build it? As gearheads we tend to jump to the technical details with little afterthought, but should you even be building that feature in the first place? How do you make that call?</p>
<p>Whether you're a one man team with a shoestring budget, or a financed startup with some runway, managing the feature backlog is more of an art than a science – it's always full of vaguely formulated ideas and it's constantly changing. Managing these priorities is as hard as it is, and if you have a team, it gets even harder: how do you make sure that everyone is aligned with the vision and the roadmap?</p>
<h4><strong>Managing the backlog: countdown to zero</strong></h4>
<p><img src="/posts/07-08/accounting.png" align="left" style="margin-right:1em;" /> A great story from the startup folklore: after closing a round of financing, the CEO brought in a big jar of marbles representing the amount of money they had in the bank and proposed that each time a project manager or a developer pitched an idea, they would have to take some marbles out of the jar (depending on the size of the project).  Nobody opposed it, but a few odd looks were exchanged.  Then six months went by, the jar was now half-full and the dynamics started to change - everyone became much more conscious of the amount left in the jar. They could now see the inevitable: the jar was not being filled up nearly as fast as it was being depleted.</p>
<p>The problem is, I think we all fall into this trap more often than not. What has changed in the fundamental goals of the company in the six months since the jar was initially full? Nothing, of course. The strategy may have shifted, the product roadmap has evolved, but the economics of running a company remained constant. Six months ago, the day that the company would cease to exist was 12 months away, 6 months later, it was simply 6 months closer.  Here's an acid test: if your project would cease to exist tomorrow, would you work on the feature you're contemplating doing today?</p>
<h4><strong>The luxury of time</strong></h4>
<p>Just because the deadline is further away does not buy you the luxury of indulging into technological desires. Unfortunately, as developers we tend to forget this, as we’re too easily distracted by the shiny technical aspects of the next greatest thing, or <a href="http://en.wikipedia.org/wiki/Optimization_(computer_science)#When_to_optimize">over optimizing</a> for the day that never comes.</p>
<p>Stop and examine what you are working on now: does it directly contribute to the success of your project today, or is it a nice to have? If you had a deadline in the immediate feature, would you still be working on it? If not, then you probably shouldn’t be doing it.</p>
<p style="text-align: center;"><img src="/posts/07-08/agile-dilbert.gif" /></p>
<h4><strong>Time & Strategy: use them to your advantage</strong></h4>
<p>Does that mean we should always focus on the short term goals? Not at all. The luxury of time is exactly that: a luxury and it should be treated as such. If you waste it, you can’t get it back. But having this luxury can also buy you a strategic advantage: you can trade short term goals for a higher return in the long term. </p>
<p>Sometimes you have to go slow to go faster. It's the lack of that regression test suite that's coming back to bite you, or perhaps a monitoring system that will save you the maintenance time – the examples are endless. The challenge is, of course, to weight the benefits of these long term goals against the possible value of shorter and quicker releases: “<em>Great companies ship.</em>” You have to be able to recognize that a technologically inferior solution delivered quickly can often outweigh a ‘cleaner’ solution – the real trick is, of course, to also have your team of gearheads understand why this is true.</p>
<p>Time can buy you the luxury of strategic objectives, but remember that today is no different than the day you’ll be taking the last pebble out of that jar, it just happens to be a few days into the future.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=fO0ycJ"><img src="http://feeds.feedburner.com/~f/igvita?i=fO0ycJ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=E1utvj"><img src="http://feeds.feedburner.com/~f/igvita?i=E1utvj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=1dS11j"><img src="http://feeds.feedburner.com/~f/igvita?i=1dS11j" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=vSH8Sj"><img src="http://feeds.feedburner.com/~f/igvita?i=vSH8Sj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=Gn9tuj"><img src="http://feeds.feedburner.com/~f/igvita?i=Gn9tuj" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/335197349" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/07/14/fighting-technological-indulgences/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F07%2F14%2Ffighting-technological-indulgences%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/07/14/fighting-technological-indulgences/</feedburner:origLink></item>
		<item>
		<title>6 Optimization Tips for Ruby MRI</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/329720039/</link>
		<comments>http://www.igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri/#comments</comments>
		<pubDate>Tue, 08 Jul 2008 11:04:56 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[mri]]></category>

		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://www.igvita.com/?p=185</guid>
		<description><![CDATA[ Every language has its idiosyncrasies and Ruby is no different, hence, below is a collection of handy optimizations to keep in mind next time you're working on a Ruby project. Majority of them appear to fall into the syntactic sugar category, but it's important to understand the motivation behind each, as there is usually [...]]]></description>
			<content:encoded><![CDATA[<p><img align="left" src="/posts/07-08/ruby.png" style="margin-right:1em;" /> Every language has its idiosyncrasies and Ruby is no different, hence, below is a collection of handy optimizations to keep in mind next time you're working on a Ruby project. Majority of them appear to fall into the syntactic sugar category, but it's important to understand the motivation behind each, as there is usually a concrete reason for the performance difference. I should also say, that this is primarily for Ruby 1.8 and you should benchmark these yourself if you're already running on the dev branch of Ruby 1.9.</p>
<h4><strong>Help the Ruby interpreter</strong></h4>
<p>This is no secret: Ruby interpreter is slow. Advances on the JRuby and Maglev front are certainly showing some very appealing performance increases, but even there, a deeper understanding of the Ruby internals is bound to help you write better and faster code. The <a href="http://en.wikipedia.org/wiki/Ruby_programming_language">Ruby Wikipedia entry</a> is a great place to start to learn about some of intricacies of Ruby. For a deeper look, Dr. Stefan Kaes's '<a href="http://safari.oreilly.com/9780321540034">Writing Efficient Ruby Code</a>', and David A. Blacks' '<a href="http://www.manning.com/black/">Ruby for Rails</a>' are must have for any Ruby developer.</p>
<h4><strong>1. Minimize searches in the abstract syntax tree</strong></h4>
<p>Ruby has a wonderful property of being highly dynamic, which in turn, allows us to create all kinds of spectacular meta-programming scenarios. However, this comes at a price of minimal runtime and compile time optimization (JRuby and some other VM's are changing this). Unlike most other languages, Ruby's MRI does not generate bytecode (<a href="http://hackety.org/2008/05/05/sneakingRubyThroughGoogleAppEngine.html">Ruby 1.9 will change this</a>), but relies solely on searching through the <a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> (AST) for virtually every method call, variable, and so on. Sounds expensive? It is. Hence, next time you're saving yourself three lines of code by writing a meta function, consider inlining the logic directly.  </p>
<h4><strong>2. Optimize for Ruby cache, avoid expensive lookups</strong></h4>
<p>To optimize against expensive searches through the AST, Ruby keeps a cache of local variables and method signatures. Hence, comparatively speaking, local variables are cheap - use them:</p>
<pre class="ruby">&nbsp;
<span style="color:#0066ff; font-weight:bold;">@var</span> = <span style="color:#996600;">&quot;local variable, which is cached by Ruby, and requires a single lookup&quot;</span>
<span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">var</span> = <span style="color:#996600;">&quot;requires walking the AST, and results in multiple lookups&quot;</span>
&nbsp;</pre>
<h4><strong>3. Interpolation over Concatenation</strong></h4>
<p>This came as a surprise to me the first time I stumbled across it: interpolated strings are faster than straight concatenation! Chris Blackburn recently wrote a <a href="http://blog.cbciweb.com/articles/2008/06/10/ruby-performance-use-double-quotes-vs-single-quotes">great blog post</a> about it, make sure to read it.</p>
<pre class="ruby">&nbsp;
<span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;This string embeds #{var1} and #{var2} through interpolation&quot;</span>  <span style="color:#008000; font-style:italic;"># faster</span>
<span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;This string concatenates &quot;</span> &lt;&lt; var1 &lt;&lt; <span style="color:#996600;">&quot; and &quot;</span> &lt;&lt; var <span style="color:#006666;">2</span>  <span style="color:#008000; font-style:italic;"># slower</span>
&nbsp;</pre>
<h4><strong>4. When possible, use destructive operations!</strong></h4>
<p>Many ruby operations have a destructive (ex: <em>gsub</em> vs <em>gsub!</em>) equivalent, and which, unfortunately are not used very often largely due to the somewhat erratic behavior: sometimes these operations return nil, sometimes they don't. However, non destructive operations (ex: gsub) duplicate your object and hence incur an expensive copy operation every time. Learn the non-nil, destructive operations and use them religiously.</p>
<pre class="ruby">&nbsp;
hash = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
hash = hash.<span style="color:#9900CC;">merge</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006666;">1</span> =&gt; <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;"># duplicates the original hash</span>
hash.<span style="color:#9900CC;">merge</span>!<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006666;">1</span> =&gt; <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;"># equivalent to previous line, and faster</span>
&nbsp;
str = <span style="color:#996600;">&quot;string to gsub&quot;</span>
str = str.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/to/, <span style="color:#996600;">'copy'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;"># duplicate string and reassigns it</span>
str.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>/to/, <span style="color:#996600;">'copy'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;"># same effect, but no object duplication</span>
&nbsp;</pre>
<h4><strong>5. Symbol.to_proc fan? Use blocks!</strong></h4>
<p>If you're a Rails developer, you've probably used Symbol.to_proc. Well, you're likely incurring an order of magnitude speed decrease when you do! Next time, use a block:</p>
<pre class="ruby">&nbsp;
<span style="color:#0066ff; font-weight:bold;">@widget_ids</span> = <span style="color:#0066ff; font-weight:bold;">@widgets</span>.<span style="color:#9900CC;">map</span><span style="color:#006600; font-weight:bold;">&#40;</span>&amp;:id<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;"># Symbol.to_proc method, order of magniture slower...</span>
<span style="color:#0066ff; font-weight:bold;">@widget_ids</span> = <span style="color:#0066ff; font-weight:bold;">@widgets</span>.<span style="color:#9900CC;">inject</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|w, a| w.<span style="color:#9900CC;">push</span><span style="color:#006600; font-weight:bold;">&#40;</span>a.<span style="color:#9900CC;">id</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#008000; font-style:italic;"># same effect, not as pretty, but much faster</span>
<span style="color:#0066ff; font-weight:bold;">@widget_ids</span> = <span style="color:#0066ff; font-weight:bold;">@widgets</span>.<span style="color:#9900CC;">collect</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|w| w.<span style="color:#9900CC;">id</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#008000; font-style:italic;"># faster, and simpler than inject</span>
<span style="color:#0066ff; font-weight:bold;">@widget_ids</span> = <span style="color:#0066ff; font-weight:bold;">@widgets</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|w| w.<span style="color:#9900CC;">id</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#008000; font-style:italic;"># yet another (faster) way to tackle the problem</span>
&nbsp;</pre>
<h4><strong>6. Benchmark everything!</strong></h4>
<p>Create a macro, stash it away in an easy to access area, or post the code for the benchmark skeleton on your wall. Anytime I have a question about Ruby performance, the answer is always less than 30 seconds away:</p>
<pre class="ruby">&nbsp;
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'benchmark'</span>
&nbsp;
n = <span style="color:#006666;">100000</span>
<span style="color:#CC00FF; font-weight:bold;">Benchmark</span>.<span style="color:#9900CC;">bm</span> <span style="color:#9966CC; font-weight:bold;">do</span> |x|
   x.<span style="color:#9900CC;">report</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'copy'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> n.<span style="color:#9900CC;">times</span> <span style="color:#9966CC; font-weight:bold;">do</span> ; h = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span>; h = h.<span style="color:#9900CC;">merge</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006666;">1</span> =&gt; <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>; <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
   x.<span style="color:#9900CC;">report</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'no copy'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> n.<span style="color:#9900CC;">times</span> <span style="color:#9966CC; font-weight:bold;">do</span> ; h = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span>; h.<span style="color:#9900CC;">merge</span>!<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006666;">1</span> =&gt; <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>; <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;">#          user        system      total        real</span>
<span style="color:#008000; font-style:italic;"># copy     0.460000   0.180000   0.640000 (  0.640692)</span>
<span style="color:#008000; font-style:italic;"># no copy  0.340000   0.120000   0.460000 (  0.463339)</span>
&nbsp;</pre>
<p>Your favorite optimization tip missing from the list? Leave a comment, let everyone know!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=2PfBOJ"><img src="http://feeds.feedburner.com/~f/igvita?i=2PfBOJ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=Oyw7mj"><img src="http://feeds.feedburner.com/~f/igvita?i=Oyw7mj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=Vl9OTj"><img src="http://feeds.feedburner.com/~f/igvita?i=Vl9OTj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=BQJ8kj"><img src="http://feeds.feedburner.com/~f/igvita?i=BQJ8kj" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=6diT4j"><img src="http://feeds.feedburner.com/~f/igvita?i=6diT4j" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/329720039" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F07%2F08%2F6-optimization-tips-for-ruby-mri%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/07/08/6-optimization-tips-for-ruby-mri/</feedburner:origLink></item>
		<item>
		<title>Splunk Your Distributed Logs in EC2</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/315351642/</link>
		<comments>http://www.igvita.com/2008/06/19/splunk-your-distributed-logs-in-ec2/#comments</comments>
		<pubDate>Thu, 19 Jun 2008 11:20:12 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Architecture]]></category>

		<category><![CDATA[aws]]></category>

		<category><![CDATA[ec2]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[splunk]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/06/19/splunk-your-distributed-logs-in-ec2/</guid>
		<description><![CDATA[ Managing log files is like herding cats, except its worse: a typical LAMP / Rails stack will easily generate a dozen logs in different locations. The fun part is, of course, the debugging and server administration tasks which involve the forensic task of tracking down each of these files and then cross-referencing timestamps to [...]]]></description>
			<content:encoded><![CDATA[<p><img align="left" src="/posts/06-08/splunk+aws+ruby.png"/> Managing log files is like herding cats, except its worse: a typical LAMP / Rails stack will easily generate a dozen logs in different locations. The fun part is, of course, the debugging and server administration tasks which involve the forensic task of tracking down each of these files and then cross-referencing timestamps to figure out what really happened. We've all dealt with this problem at one point or another.</p>
<p>Hence, when I recently stumbled on <a href="http://www.splunk.com/">Splunk</a>, I knew I had to try it - <a href="http://www.splunk.com/article/2186">it</a>, <a href="http://www.splunk.com/article/205">looked</a>, <a href="http://interop.demo.splunk.com/login">awesome</a>. The setup was a breeze and I was up and running in no time - no more fgrep / egrep for me! If you want to give it a try, take a look at Michael Wilde's video (<a href="http://blogs.splunk.com/thewilde/2008/06/17/splunk-ninja-cloud-power-splunkin-with-amazons-ec2/">Splunkin' with Amazon EC2</a>), which he posted just a few days ago. Michael provides a great walkthrough, but I think he overlooked an awesome feature of Splunk, which is especially useful for the EC2 environment, and one we're planning to make heavy use of at AideRSS: distributed logging over TCP!</p>
<h4><strong>Managing Distributed Logs from the Cloud</strong></h4>
<p style="text-align: center;"><a target="_blank" href="/posts/06-08/splunk+ruby.png"><img style="border: 1px solid rgb(153, 153, 153); padding: 1px;" src="/posts/06-08/splunk+ruby-small.png"/></a></p>
<p>Managing logs is hard as it is, and now imagine you have several (dozen) servers in EC2, the process becomes a chore, the debugging is hard, and frustration abounds. To address this problem, I've setup Splunk to <a href="http://www.splunk.com/docs/view/data/2/6">listen on a TCP port</a> for any network traffic - if all others servers log to this host, then you will have a centralized, indexed log repository for all of your services. A simple Ruby-based <em>NetworkLogger</em> class later, and we're in business:</p>
<p><a href="javascript:showme('7848_1');"> <b>> networklogger.rb</b></a>
<div style=" background:white;" id=7848_1>
<pre class="ruby"><span style="color:#008000; font-style:italic;"># igvita.com (Ilya Grigorik)</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'socket'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> NetworkLogger
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>host = <span style="color:#996600;">'localhost'</span>, port = <span style="color:#996600;">'8888'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@socket</span> = TCPSocket.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>host, port<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> log<span style="color:#006600; font-weight:bold;">&#40;</span>level, msg<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@socket</span>.<span style="color:#9900CC;">write</span> <span style="color:#996600;">&quot;#{Time.new.strftime(&quot;</span>%H:%M:%S<span style="color:#996600;">&quot;)} (#{level}): #{msg}<span style="color:#000099;">\\n</span>&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> method_missing<span style="color:#006600; font-weight:bold;">&#40;</span>method, *args<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> method.<span style="color:#9900CC;">to_s</span> =~ /<span style="color:#006600; font-weight:bold;">&#40;</span>info|debug|warn|error<span style="color:#006600; font-weight:bold;">&#41;</span>/i
      <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">log</span><span style="color:#006600; font-weight:bold;">&#40;</span>method.<span style="color:#9900CC;">to_s</span>, args<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
logger = NetworkLogger.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'localhost'</span>, <span style="color:#006666;">9998</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Send log messages to remote Splunk server </span>
logger.<span style="color:#9900CC;">info</span> <span style="color:#996600;">&quot;This is in INFO message&quot;</span>
logger.<span style="color:#9900CC;">debug</span> <span style="color:#996600;">&quot;This is a DEBUG message&quot;</span>
logger.<span style="color:#9900CC;">warn</span> <span style="color:#996600;">&quot;This is a WARNING message&quot;</span>
logger.<span style="color:#9900CC;">error</span> <span style="color:#996600;">&quot;Uh oh! This is an ERROR message&quot;</span></pre>
</div>
<p><div class='download-link'>
							<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/code/networklogger.rb'><img alt='Download' class='leftalign' src='http://www.igvita.com/wp-content/plugins/dBeautifier/icons/downloads.png' /></a>
							<h4>
								<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/code/networklogger.rb'>networklogger.rb (NetworkLogger source)</a>
							</h4><p>Downloads: 222 File Size: 0.7 KB </p>
						</div></p>
<p>It's a simple example, but it highlights the possibilities - you can stream any set of logs to a centralized server for easy debugging, live monitoring, and alerts and notifications. Best of all, it's a <a href="http://www.splunk.com/article/2018">free solution</a> as long as you stay below 500mb of indexed log data, per day.</p>
<p><em><strong>Update:</strong></em> Michael Wilde posted posted a video reply with a demo of what he considers the coolest feature of Splunk to be: transactions. I didn't know about, and have to agree, thanks Michael! </p>
<p style="text-align: center;"><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="370" id="viddler"><param name="movie" value="http://www.viddler.com/player/d247ad0/" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><embed src="http://www.viddler.com/player/d247ad0/" width="437" height="370" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" name="viddler" ></embed></object></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=4EiILI"><img src="http://feeds.feedburner.com/~f/igvita?i=4EiILI" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=z4tVTi"><img src="http://feeds.feedburner.com/~f/igvita?i=z4tVTi" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=wHyD4i"><img src="http://feeds.feedburner.com/~f/igvita?i=wHyD4i" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=B7ZRHi"><img src="http://feeds.feedburner.com/~f/igvita?i=B7ZRHi" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=saT0Ii"><img src="http://feeds.feedburner.com/~f/igvita?i=saT0Ii" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/315351642" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/06/19/splunk-your-distributed-logs-in-ec2/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F06%2F19%2Fsplunk-your-distributed-logs-in-ec2%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/06/19/splunk-your-distributed-logs-in-ec2/</feedburner:origLink></item>
		<item>
		<title>Tumblr, RMagick and a Photo Frame!</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/307376725/</link>
		<comments>http://www.igvita.com/2008/06/08/tumblr-rmagick-and-a-photo-frame/#comments</comments>
		<pubDate>Sun, 08 Jun 2008 14:26:10 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Projects]]></category>

		<category><![CDATA[rmagick]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[tumblr]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/06/08/tumblr-rmagick-and-a-photo-frame/</guid>
		<description><![CDATA[ Over the course of the past year or so, I got myself into a habit of using Tumblr for storing insightful snippets and quotes from my daily endeavours on the internet. Usually, this entails saving a paragraph (too long for tweet, and not enough for del.icio.us) so I can revisit it later.
However, having Tumblr [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://flickr.com/photos/ig/2559253173/"><img src="http://farm4.static.flickr.com/3049/2559253173_c2bc1d9566_m.jpg" style="padding: 3px; border: 1px solid #ccc; margin-right:1em;" align="left" /></a> Over the course of the past year or so, I got myself into a habit of <a href="http://igrigorik.tumblr.com">using Tumblr</a> for storing insightful snippets and quotes from my daily endeavours on the internet. Usually, this entails saving a paragraph (too long for <a href="http://www.twitter.com/igrigorik">tweet</a>, and not enough for del.icio.us) so I can revisit it later.</p>
<p>However, having Tumblr to save the quotes is nice, but I rarely (if ever) went back to read them. Pondering this dilemma, I spotted my <a href="http://www.amazon.com/dp/B000HWS0Q2?smid=ATVPDKIKX0DER&tag=nextag-ce-tier2-20&linkCode=asn">Phillips digital photo frame</a>, and a quick weekend project was born: Tumblr API, RMagick to render the images, and an SD card full of wisdom and quotes for easy consumption!</p>
<h4><strong>Retrieving quotes from Tumblr API</strong></h4>
<p>Retrieving your content from Tumblr is about as easy as it can get: one GET request, with a few query parameters. In return you get an XML file with the quotes, the source link, publication time, and much more. To parse the XML response, <a href="http://code.whytheluckystiff.net/hpricot/">HPricot</a> comes to the rescue:</p>
<p><a href="javascript:showme('7456_1');"> <b>> tumblr-api.rb</b></a>
<div style=" background:white;" id=7456_1>
<pre class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'open-uri'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'hpricot'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'cgi'</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># read last 5 quotes</span>
doc = Hpricot.<span style="color:#9900CC;">XML</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;http://username.tumblr.com/api/read?type=quote&amp;num=5&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># iterate and clean up (unescape HTML, and remove HTML entities)</span>
<span style="color:#006600; font-weight:bold;">&#40;</span>doc/<span style="color:#996600;">'post'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |post|
    text = <span style="color:#CC00FF; font-weight:bold;">CGI</span>::unescapeHTML<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span>post/<span style="color:#996600;">'quote-text'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">inner_html</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/&amp;<span style="color:#006600; font-weight:bold;">&#91;</span>^;<span style="color:#006600; font-weight:bold;">&#93;</span>*;?/,<span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    source = <span style="color:#CC00FF; font-weight:bold;">CGI</span>::unescapeHTML<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span>post/<span style="color:#996600;">'quote-source'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">inner_html</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/\\&lt;.<span style="color:#9900CC;">*</span>?\\&gt;/, <span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/&amp;<span style="color:#006600; font-weight:bold;">&#91;</span>^;<span style="color:#006600; font-weight:bold;">&#93;</span>*;?/,<span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">strip</span>
&nbsp;
    <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;Processing: #{post['id']}<span style="color:#000099;">\\n</span>&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;</pre>
</div>
<h4><strong>Rendering wisdom with RMagick</strong></h4>
<p>Once the data is cleaned up, we can get to the rendering step. Installing <a href="http://rmagick.rubyforge.org/install-faq.html">RMagick</a> can be a dreadful experience, but it appears that as of 2.x release, this process has been vastly improved - everything worked on the first try!</p>
<p>To render the final image, I've decided to adopt the simplest possible route: render each component as a separate image (quote text, background, source link, etc), and then merge the images as layers into a single file. Easier said than done! RMagick is not for the faint of heart, and to my surprise, did not have the concept of a text box (it can only render contiguous lines), unless you use the <i>annotate</i> method:</p>
<p><a href="javascript:showme('7456_2');"> <b>> rmagick-quote.rb</b></a>
<div style=" background:white;" id=7456_2>
<pre class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rmagick'</span>
<span style="color:#9966CC; font-weight:bold;">include</span> Magick
&nbsp;
text = <span style="color:#996600;">&quot;A goal is a dream with deadline&quot;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># courtesy of http://blog.choonkeat.com/weblog/2007/02/rmagick-renderi.html</span>
<span style="color:#008000; font-style:italic;"># - render the text in a 500x430 box, and truncate if needed</span>
quote = render_cropped_text<span style="color:#006600; font-weight:bold;">&#40;</span>text, <span style="color:#006666;">500</span>, <span style="color:#006666;">430</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |img|
   img.<span style="color:#9900CC;">fill</span> = <span style="color:#996600;">&quot;#ffffff&quot;</span> <span style="color:#008000; font-style:italic;"># font color</span>
   img.<span style="color:#9900CC;">background_color</span> = <span style="color:#996600;">&quot;transparent&quot;</span>
   img.<span style="color:#9900CC;">pointsize</span> = <span style="color:#006666;">23</span>
   img.<span style="color:#9900CC;">antialias</span> = <span style="color:#0000FF; font-weight:bold;">true</span>
   img.<span style="color:#9900CC;">font</span> = <span style="color:#996600;">&quot;Helvetica&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
quote.<span style="color:#9900CC;">write</span> <span style="color:#996600;">&quot;text.png&quot;</span>
&nbsp;</pre>
</div>
<p><div class='download-link'>
							<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/tumblr.zip'><img alt='Download' class='leftalign' src='http://www.igvita.com/wp-content/plugins/dBeautifier/icons/downloads.png' /></a>
							<h4>
								<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/tumblr.zip'>tumblr.zip (full implementation)</a>
							</h4><p>Downloads: 85 File Size: 135.8 KB </p>
						</div></p>
<p>It's not optimized, but it got the job done: ~160 quotes on an SD card, rotating at random intervals for my enjoyment. Next iteration, automated updates of quotes on my photo frame via RSS and WiFi - any volunteers to write a <a href="http://sinatrarb.com/Home">Sinatra app</a>? I can't wait until <a href="http://www.dlink.com/products/?sec=0&pid=654">D-Link DSM-210</a> hits the streets!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=VWEMkI"><img src="http://feeds.feedburner.com/~f/igvita?i=VWEMkI" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=CWQNJi"><img src="http://feeds.feedburner.com/~f/igvita?i=CWQNJi" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=QMIEzi"><img src="http://feeds.feedburner.com/~f/igvita?i=QMIEzi" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=7qsoOi"><img src="http://feeds.feedburner.com/~f/igvita?i=7qsoOi" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=knnX4i"><img src="http://feeds.feedburner.com/~f/igvita?i=knnX4i" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/307376725" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/06/08/tumblr-rmagick-and-a-photo-frame/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F06%2F08%2Ftumblr-rmagick-and-a-photo-frame%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/06/08/tumblr-rmagick-and-a-photo-frame/</feedburner:origLink></item>
		<item>
		<title>Ruby Heroes &amp; RailsConf ‘08 Day 1</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/301924412/</link>
		<comments>http://www.igvita.com/2008/05/31/ruby-heroes-railsconf-08-day-1/#comments</comments>
		<pubDate>Sat, 31 May 2008 16:29:07 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[award]]></category>

		<category><![CDATA[railsconf]]></category>

		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/05/31/ruby-heroes-railsconf-08-day-1/</guid>
		<description><![CDATA[ Wow, this was a nice surprise last night - a Ruby Hero award at RailsConf '08! The group of guys I got to share the stage with was unbelievable: Ryan Bates, Evan Weaver, Yehuda Katz, plus two more  winners who couldn't make it to RailsConf. It's amazing to see the community support, and [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://flickr.com/photos/x180/2537415785/"><img src="http://farm4.static.flickr.com/3212/2537415785_6bc97fe102_m.jpg" align="left" style="padding:3px; margin-right: 1em; border: 1px solid #ccc;"/></a> Wow, this was a nice surprise last night - a <a href="http://www.rubyheroes.com/">Ruby Hero</a> award at RailsConf '08! The group of guys I got to share the stage with was unbelievable: <a href="http://railscasts.com/">Ryan Bates</a>, <a href="http://blog.EvanWeaver.com">Evan Weaver</a>, <a href="http://yehudakatz.com/">Yehuda Katz</a>, plus two more  winners who couldn't make it to RailsConf. It's amazing to see the community support, and kudos to everyone who voted, attended, and contributed to the conversation - you guys make it happen. </p>
<p>If you're looking for Rails coverage, <a href="http://twitter.com/igrigorik">follow me on Twitter</a> (my laptop decided to take a nap for a few days, hence broadcasting from my Blackberry). For more twitter news, make sure to also check out the <a href="http://summize.com/search?q=railsconf">summize stream</a>.</p>
<p>A few topics that generated a lot of talk at RailsConf yesterday:</p>
<ul>
<li><a href="http://blog.obiefernandez.com/content/2008/05/maglev-is-gemst.html">MagLev is Gemstone/S for Ruby, Huge News</a></li>
<li><a href="http://gilesbowkett.blogspot.com/2008/05/twitter-response-to-railsconf-2008.html">Twitter response to MagLev presentation</a></li>
<li><a href="http://www.iunknown.com/2008/05/ironruby-and-rails.html">IronRuby and Rails</a> - watch for Silverline, very cool project (ARAX).</li>
<li>Drew Blas <a href="http://rubyflow.com/items/415">has great coverage</a> of the conference - keep it up!</li>
<li><a href="http://onrails.org/articles/2008/05/31/railsconf-2008-david-heinemeier-hanssons-keynote-video">DHH keynote @ RailsConf '08</a></li>
</ul>
<p>Last but not least, if you're at RailsConf and spot me in the crowd, come say hello! Talks I'm looking forward to attending today:</p>
<ul>
<li>Assembling Pages Last: Edge Cache, ESI & Rails - Aaron Batalion</li>
<li>Asynchronous Processing with Ruby on Rails - Jonathan Dahi</li>
<li>Quick and Easy Custom Servers using EventMachine - Soctt Fleckenstein</li>
<li>Custom Nginx Modules: Accelerate Rails, HTTP tricks - Adam Wiggins</li>
<li>The Great Test Framework Dance-off - John Susser</li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=2XJ90H"><img src="http://feeds.feedburner.com/~f/igvita?i=2XJ90H" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=z7YlKh"><img src="http://feeds.feedburner.com/~f/igvita?i=z7YlKh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=myBHKh"><img src="http://feeds.feedburner.com/~f/igvita?i=myBHKh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=qqR7Uh"><img src="http://feeds.feedburner.com/~f/igvita?i=qqR7Uh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=zXT7fh"><img src="http://feeds.feedburner.com/~f/igvita?i=zXT7fh" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/301924412" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/05/31/ruby-heroes-railsconf-08-day-1/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F05%2F31%2Fruby-heroes-railsconf-08-day-1%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/05/31/ruby-heroes-railsconf-08-day-1/</feedburner:origLink></item>
		<item>
		<title>Ruby EventMachine - The Speed Demon</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/299200675/</link>
		<comments>http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/#comments</comments>
		<pubDate>Tue, 27 May 2008 16:47:32 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[evented]]></category>

		<category><![CDATA[eventmachine]]></category>

		<category><![CDATA[reactor]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/</guid>
		<description><![CDATA[Ruby EventMachine is a framework, which depending on who you talk to, either yields a lot of excitement (Evented Mongrel, Analogger, Evented Starling, etc.) or its fair share of criticism. In part, the FUD is due to the mismatch of the language used, and the underlying implementation - namely, the Reactor pattern. 

The reactor design [...]]]></description>
			<content:encoded><![CDATA[<p>Ruby <a href="http://rubyeventmachine.com/">EventMachine</a> is a framework, which depending on who you talk to, either yields a lot of excitement (<a href="http://swiftiply.swiftcore.org/mongrel.html">Evented Mongrel</a>, <a href="http://analogger.swiftcore.org/index.html">Analogger</a>, <a href="http://github.com/defunkt/starling/tree/master">Evented Starling</a>, etc.) or its fair share of criticism. In part, the FUD is due to the mismatch of the language used, and the underlying implementation - namely, the <a href="http://en.wikipedia.org/wiki/Reactor_pattern">Reactor pattern</a>. </p>
<p style="text-align:center;"><img src="/posts/05-08/EventMachineLogo.png" alt="EventMachine" /></p>
<blockquote><p>The reactor design pattern is a concurrent programming pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.</p></blockquote>
<h4><strong>Why Reactor to begin with?</strong></h4>
<p>Steeped in the tradition of forking / threaded web-servers I found myself rather surprised when I joined one of the research projects at University of Waterloo a couple of years back: we were benchmarking different web-server architectures, and top performers were all event-driven servers.</p>
<p>As I pestered everyone with questions, I quickly realized why - in an environment with hundreds of thousands requests a second, forking and context switching associated with thread management become prohibitively expensive (fork is worst performer, as it does a memory copy on the parent process every time). Whereas by comparison, a tight and highly optimized event-loop really shines when it comes to performance under heavy loads.</p>
<h4><strong>EventMachine and Reactor pattern</strong></h4>
<p>Listening to a couple of recent presentations on different Ruby application server alternatives, I've come across a consistent comment: <em>"Evented servers are really good for very light requests, but if you have a long-running request, it falls down on its face."</em> Technically, valid, but in practice, not necessarily true. Let's start with the simplest example:</p>
<p><a href="javascript:showme('280_1');"> <b>> em-http.rb</b></a>
<div style=" background:white;" id=280_1>
<pre class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'eventmachine'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'evma_httpserver'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> Handler  &lt; <span style="color:#6666ff; font-weight:bold;">EventMachine::Connection</span>
  <span style="color:#9966CC; font-weight:bold;">include</span> <span style="color:#6666ff; font-weight:bold;">EventMachine::HttpServer</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> process_http_request
    resp = <span style="color:#6666ff; font-weight:bold;">EventMachine::DelegatedHttpResponse</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#0000FF; font-weight:bold;">self</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    <span style="color:#CC0066; font-weight:bold;">sleep</span> <span style="color:#006666;">2</span> <span style="color:#008000; font-style:italic;"># Simulate a long running request</span>
&nbsp;
    resp.<span style="color:#9900CC;">status</span> = <span style="color:#006666;">200</span>
    resp.<span style="color:#9900CC;">content</span> = <span style="color:#996600;">&quot;Hello World!&quot;</span>
    resp.<span style="color:#9900CC;">send_response</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
EventMachine::run <span style="color:#006600; font-weight:bold;">&#123;</span>
  EventMachine.<span style="color:#9900CC;">epoll</span>
  EventMachine::start_server<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;0.0.0.0&quot;</span>, <span style="color:#006666;">8080</span>, Handler<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;Listening...&quot;</span>
<span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Benchmarking results:</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#008000; font-style:italic;"># &gt; ab -c 5 -n 10 &quot;http://127.0.0.1:8080/&quot;</span>
<span style="color:#008000; font-style:italic;"># &gt; Concurrency Level:      5</span>
<span style="color:#008000; font-style:italic;"># &gt; Time taken for tests:   20.6246 seconds</span>
<span style="color:#008000; font-style:italic;"># &gt; Complete requests:      10</span>
&nbsp;
&nbsp;</pre>
</div>
<p>Here we've built the simplest possible HTTP web-server using EventMachine. To test it, we ran ab (<a href="http://httpd.apache.org/docs/2.0/programs/ab.html">Apache Bench</a>), and set the concurrency to 5 (-c 5), and number of requests to 10 (-n 10). Time to process is ~20 seconds, which makes sense, because as expected the Reactor is processing each request in synchronous fashion, effectively overriding our concurrency setting to 1. Hence, 10 requests, 2 seconds each, and the math works out!</p>
<h4><strong>EventMachine: Reactor with lightweight concurrency?</strong></h4>
<p>The synchronous nature of the Reactor pattern is the bottleneck in the previous example, and that's where EventMachine deviates from the purist pattern. Specifically, it provides a mechanism by which it is also possible to dispatch the request to a pool of green Ruby threads (20 by default):</p>
<p><a href="javascript:showme('280_2');"> <b>> em-http-pool.rb</b></a>
<div style=" background:white;" id=280_2>
<pre class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'eventmachine'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'evma_httpserver'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> Handler  &lt; <span style="color:#6666ff; font-weight:bold;">EventMachine::Connection</span>
  <span style="color:#9966CC; font-weight:bold;">include</span> <span style="color:#6666ff; font-weight:bold;">EventMachine::HttpServer</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> process_http_request
    resp = <span style="color:#6666ff; font-weight:bold;">EventMachine::DelegatedHttpResponse</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#0000FF; font-weight:bold;">self</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    <span style="color:#008000; font-style:italic;"># Block which fulfills the request</span>
    operation = <span style="color:#CC0066; font-weight:bold;">proc</span> <span style="color:#9966CC; font-weight:bold;">do</span>
	<span style="color:#CC0066; font-weight:bold;">sleep</span> <span style="color:#006666;">2</span> <span style="color:#008000; font-style:italic;"># simulate a long running request</span>
&nbsp;
        resp.<span style="color:#9900CC;">status</span> = <span style="color:#006666;">200</span>
        resp.<span style="color:#9900CC;">content</span> = <span style="color:#996600;">&quot;Hello World!&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    <span style="color:#008000; font-style:italic;"># Callback block to execute once the request is fulfilled</span>
    callback = <span style="color:#CC0066; font-weight:bold;">proc</span> <span style="color:#9966CC; font-weight:bold;">do</span> |res|
    	resp.<span style="color:#9900CC;">send_response</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    <span style="color:#008000; font-style:italic;"># Let the thread pool (20 Ruby threads) handle request</span>
    EM.<span style="color:#9900CC;">defer</span><span style="color:#006600; font-weight:bold;">&#40;</span>operation, callback<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
EventMachine::run <span style="color:#006600; font-weight:bold;">&#123;</span>
  EventMachine.<span style="color:#9900CC;">epoll</span>
  EventMachine::start_server<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;0.0.0.0&quot;</span>, <span style="color:#006666;">8081</span>, Handler<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;Listening...&quot;</span>
<span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Benchmarking results:</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#008000; font-style:italic;"># &gt; ab -c 5 -n 10 &quot;http://127.0.0.1:8081/&quot;</span>
<span style="color:#008000; font-style:italic;"># &gt; Concurrency Level:      5</span>
<span style="color:#008000; font-style:italic;"># &gt; Time taken for tests:   4.21405 seconds</span>
<span style="color:#008000; font-style:italic;"># &gt; Complete requests:      10</span>
&nbsp;</pre>
</div>
<p>Once again, 10 requests in total, concurrency set to 5, but this time we are done in ~4 seconds! This means our new server is processing requests in parallel, much like your typical, best of breed <a href="http://mongrel.rubyforge.org/">Mongrel</a>. Not quite the Reactor pattern EventMachine advertises, but a very powerful feature nonetheless - now you can see where all the FUD is coming from.</p>
<h4><strong>Deferrable: Concurrency with no threads</strong></h4>
<p>Borrowing heavily from <a href="http://twistedmatrix.com/trac/">Twisted</a>, a Python event-driven network programming framework, EventMachine also includes a <a href="http://rubyeventmachine.com/browser/trunk/DEFERRABLES">Deferrable module</a>, which in some cases allows us to get all the benefits of concurrent processing without any threading overhead!</p>
<blockquote><p>The Deferrable pattern allows you to specify any number of Ruby code blocks (callbacks or errbacks) that will be executed at some future time when the status of the Deferrable object changes. How might that be useful? Well, imagine that you're implementing an HTTP server, but you need to make a call to some other server in order to fulfill a client request.</p></blockquote>
<p><a href="javascript:showme('280_3');"> <b>> em-http-deferrable.rb</b></a>
<div style=" background:white;" id=280_3>
<pre class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'eventmachine'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'evma_httpserver'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> Handler  &lt; <span style="color:#6666ff; font-weight:bold;">EventMachine::Connection</span>
  <span style="color:#9966CC; font-weight:bold;">include</span> <span style="color:#6666ff; font-weight:bold;">EventMachine::HttpServer</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> process_http_request
    resp = <span style="color:#6666ff; font-weight:bold;">EventMachine::DelegatedHttpResponse</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#0000FF; font-weight:bold;">self</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    <span style="color:#008000; font-style:italic;"># query our threaded server (max concurrency: 20)</span>
    http = <span style="color:#6666ff; font-weight:bold;">EM::Protocols::HttpClient</span>.<span style="color:#9900CC;">request</span><span style="color:#006600; font-weight:bold;">&#40;</span>
	      <span style="color:#ff3333; font-weight:bold;">:host</span>=&gt;<span style="color:#996600;">&quot;localhost&quot;</span>,
              <span style="color:#ff3333; font-weight:bold;">:port</span>=&gt;<span style="color:#006666;">8081</span>,
              <span style="color:#ff3333; font-weight:bold;">:request</span>=&gt;<span style="color:#996600;">&quot;/&quot;</span>
           <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    <span style="color:#008000; font-style:italic;"># once download is complete, send it to client</span>
    http.<span style="color:#9900CC;">callback</span> <span style="color:#9966CC; font-weight:bold;">do</span> |r|
     	resp.<span style="color:#9900CC;">status</span> = <span style="color:#006666;">200</span>
        resp.<span style="color:#9900CC;">content</span> = r<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:content</span><span style="color:#006600; font-weight:bold;">&#93;</span>
        resp.<span style="color:#9900CC;">send_response</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
EventMachine::run <span style="color:#006600; font-weight:bold;">&#123;</span>
  EventMachine.<span style="color:#9900CC;">epoll</span>
  EventMachine::start_server<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;0.0.0.0&quot;</span>, <span style="color:#006666;">8082</span>, Handler<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;Listening...&quot;</span>
<span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Benchmarking results:</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#008000; font-style:italic;"># &gt; ab -c 20 -n 40 &quot;http://127.0.0.1:8082/&quot;</span>
<span style="color:#008000; font-style:italic;"># &gt; Concurrency Level:      20</span>
<span style="color:#008000; font-style:italic;"># &gt; Time taken for tests:   4.41321 seconds</span>
<span style="color:#008000; font-style:italic;"># &gt; Complete requests:      40</span>
&nbsp;</pre>
</div>
<p>No threading, and yet we still finish 40 requests in ~4 seconds - the only limitation is the threaded server we built in the previous example, which maxes out at 20 concurrent requests. Magic, almost! This is the beauty of EventMachine: if you can structure your worker to defer, or block on a socket, the Reactor loop will continue processing other incoming requests. When the deferred worker is done, it generates a success message and reactor sends back the response. The sky is the limit here, no Ruby threads, no synchronous processing. For a great example of this pattern, take a close look at <a href="http://blog.nominet.org.uk/tech/2007/10/12/dnsruby-and-eventmachine/">Dnsruby</a>.</p>
<p><div class='download-link'>
							<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/eventmachine.zip'><img alt='Download' class='leftalign' src='http://www.igvita.com/wp-content/plugins/dBeautifier/icons/downloads.png' /></a>
							<h4>
								<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/eventmachine.zip'>eventmachine.zip (Server implementations)</a>
							</h4><p>Downloads: 278 File Size: 1.9 KB </p>
						</div></p>
<h4><strong>EventMachine is a speed demon!</strong></h4>
<p>For more information on EventMachine make sure to check out the <a href="http://rubyeventmachine.com/">documentation and a few examples</a>. Likewise, <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=230001">Bruce Eckel's article on Twisted</a> is well worth a read if you're interested in learning more about the Deferred pattern. Last but not least, kudos to <a href="http://rubyforge.org/users/blackhedd/">Francis Cianfrocca</a> for the great framework, and his time to help me wrap my head around it! </p>
<p>Next time you hear someone shoot down an event-driven server, please (politely) correct them! </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=S8EZLH"><img src="http://feeds.feedburner.com/~f/igvita?i=S8EZLH" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=y3K93h"><img src="http://feeds.feedburner.com/~f/igvita?i=y3K93h" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=bu9wkh"><img src="http://feeds.feedburner.com/~f/igvita?i=bu9wkh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=w81ekh"><img src="http://feeds.feedburner.com/~f/igvita?i=w81ekh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=ta0Srh"><img src="http://feeds.feedburner.com/~f/igvita?i=ta0Srh" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/299200675" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F05%2F27%2Fruby-eventmachine-the-speed-demon%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/</feedburner:origLink></item>
		<item>
		<title>Load Balancing &amp; QoS with HAProxy</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/289383077/</link>
		<comments>http://www.igvita.com/2008/05/13/load-balancing-qos-with-haproxy/#comments</comments>
		<pubDate>Tue, 13 May 2008 11:48:37 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Architecture]]></category>

		<category><![CDATA[haproxy]]></category>

		<category><![CDATA[nginx]]></category>

		<category><![CDATA[proxy]]></category>

		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/05/13/load-balancing-qos-with-haproxy/</guid>
		<description><![CDATA[
A brand new Rails/Merb app you put together over a weekend, a pack of Mongrels, a reverse proxy (like Nginx), and you're up and running. Well, almost, what about that one request that tends to run forever, often forcing the user to double check their internet connection? Response time is king, and you always want [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align:center;"><a href="/posts/05-08/haproxy-large.png" target="_blank"><img src="/posts/05-08/haproxy.png" style="border: 1px solid #999; padding: 1px;" /></a></p>
<p>A brand new Rails/Merb app you put together over a weekend, a pack of Mongrels, a reverse proxy (like <a href="http://wiki.codemongers.com/Main">Nginx</a>), and you're up and running. Well, almost, what about that one request that tends to run forever, often forcing the user to double check their internet connection? Response time is king, and you always want to make sure that your site feel snappy to the user. Did you know that Flickr optimizes all of their pages to render in sub 250ms?</p>
<p>When you're fighting with response times, the worst thing you can possibly do is queue up another request behind an already long running process. Not only does the first request take forever, but everyone else must wait in line for it to finish as well! To mitigate the problem <a href="http://haproxy.1wt.eu/">HAProxy</a> goes beyond a simple round-robin scheduler, and implements a very handy feature: <strong>intelligent request queuing</strong>!</p>
<h4><strong>HAProxy Request Queuing</strong></h4>
<p><img align="left" src="/posts/05-08/haproxy-diagram.png" /><br />
<strong>Usual (bad) scenario:</strong> 2 application servers, each capable of serving 5 concurrent requests, and a reverse proxy (Nginx, Apache, Pound, etc) in front, which distributes request in usual round-robin fashion (a,b,a,b, ...). A long running request hits our application, gets to the head of the app. server queue and begins processing. Alas, now everyone else queued on that server is waiting for it to finish! Usual scenario and poor user experience. (For the astute reader: yes, the concurrency on the server is usually greater than 1, but Rails in particular has some nasty mutex locks deep inside. Hence, a long running database call can very quickly render the entire app. server incapable of doing anything else.)</p>
<p><strong>HAProxy (good) request queuing:</strong> instead of blindly passing requests to each app. server, in round-robin fashion, HAProxy allows us to limit the number of outstanding connections between the client and the server. For example, we can specify that each app server may only have two outstanding requests (which means that at most 4 jobs will be queued on our two application servers), and all other clients will wait in the HAProxy queue for the first available app. server. Beautiful! If one of our app. servers is taking a long time to respond, at most only one other request will be affected and everyone else will be processed by the first available server in our cluster.</p>
<p>Sample config to illustrate the functionality (download full config below):</p>
<p><a href="javascript:showme('2991_1');"> <b>> haproxy.conf</b></a>
<div style=" background:white;" id=2991_1>
<pre class="ruby">listen app_a_proxy <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8100</span>
  <span style="color:#008000; font-style:italic;"># - equal weights on all servers</span>
  <span style="color:#008000; font-style:italic;"># - queue requests on HAPRoxy queue once maxconn limit on the appserver is reached</span>
  <span style="color:#008000; font-style:italic;"># - minconn dynamically scales the connection concurrency (bound my maxconn) depending on size of HAProxy queue</span>
  <span style="color:#008000; font-style:italic;"># - check health of app. server every 20 seconds</span>
&nbsp;
  server a1 <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8010</span> weight <span style="color:#006666;">1</span> minconn <span style="color:#006666;">3</span> maxconn <span style="color:#006666;">6</span> check inter <span style="color:#006666;">20000</span>
  server a1 <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8010</span> weight <span style="color:#006666;">1</span> minconn <span style="color:#006666;">3</span> maxconn <span style="color:#006666;">6</span> check inter <span style="color:#006666;">20000</span>
&nbsp;
listen app_b_proxy <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8200</span>
  <span style="color:#008000; font-style:italic;"># - second cluster of servers, for another app or a long running tasks</span>
&nbsp;
  server b1 <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8050</span> weight <span style="color:#006666;">1</span> minconn <span style="color:#006666;">1</span> maxconn <span style="color:#006666;">3</span> check inter <span style="color:#006666;">40000</span>
  server b2 <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8051</span> weight <span style="color:#006666;">1</span> minconn <span style="color:#006666;">1</span> maxconn <span style="color:#006666;">3</span> check inter <span style="color:#006666;">40000</span>
  server b3 <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8052</span> weight <span style="color:#006666;">1</span> minconn <span style="color:#006666;">1</span> maxconn <span style="color:#006666;">3</span> check inter <span style="color:#006666;">40000</span>
&nbsp;</pre>
</div>
<h4><strong>QoS with HAProxy and Nginx</strong></h4>
<p>Do you want to guarantee best performance to a sub section of your site? With a little extra work on your HTTP server (Nginx in this example), we can distribute the load between different Mongrel clusters, each hidden behind a HAProxy interface:</p>
<p><a href="javascript:showme('2991_2');"> <b>> nginx-haproxy.conf</b></a>
<div style=" background:white;" id=2991_2>
<pre class="ruby"><span style="color:#008000; font-style:italic;"># ... nginx configuration</span>
&nbsp;
upstream fast_mongrels  <span style="color:#006600; font-weight:bold;">&#123;</span> server <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8100</span>; <span style="color:#006600; font-weight:bold;">&#125;</span>
upstream slow_mongrels <span style="color:#006600; font-weight:bold;">&#123;</span> server <span style="color:#006666;">127.0</span><span style="color:#006666;">.0</span><span style="color:#006666;">.1</span>:<span style="color:#006666;">8200</span>; <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
server <span style="color:#006600; font-weight:bold;">&#123;</span>
  listen <span style="color:#006666;">80</span>;
&nbsp;
  location /main <span style="color:#006600; font-weight:bold;">&#123;</span>
     proxy_pass http://fast_mongrels;
     <span style="color:#9966CC; font-weight:bold;">break</span>;
  <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
  location /slow <span style="color:#006600; font-weight:bold;">&#123;</span>
     proxy_pass http://slow_mongrels;
     <span style="color:#9966CC; font-weight:bold;">break</span>;
  <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># ... nginx config continues</span>
&nbsp;</pre>
</div>
<p>Take a close look at the earlier HAProxy config: <strong>app_b_proxy</strong> cluster has lower <em>maxconn</em> (local request queue) of 3 requests, and also features more app. servers  to process the long-running tasks. This way, anytime a user requests '/slow', they will be sent to our dedicated <em>app_b_proxy</em> and the load will be spread between 3 dedicated servers. Meanwhile, the rest of our site is completely unaffected, as it is served by a different cluster!</p>
<p><div class='download-link'>
							<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/igvita-haproxy.zip'><img alt='Download' class='leftalign' src='http://www.igvita.com/wp-content/plugins/dBeautifier/icons/downloads.png' /></a>
							<h4>
								<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/igvita-haproxy.zip'>igvita-haproxy.zip (Full Nginx + HAProxy configs)</a>
							</h4><p>Downloads: 528 File Size: 1.3 KB </p>
						</div></p>
<h4><strong>Hidden Gems in Nginx and HAProxy</strong></h4>
<p>Make sure to read the detailed overview of the <a href="http://haproxy.1wt.eu/download/1.3/doc/architecture.txt">architecture and many great examples</a> of using HAProxy in the wild, as well as, study the <a href="http://haproxy.1wt.eu/download/1.3/doc/configuration.txt">many configuration options</a> available for more hidden goodies.</p>
<p>Last but not least, it's worth mentioning that you can get similar functionality in Nginx directly with the '<a href="http://brainspl.at/articles/2007/11/09/a-fair-proxy-balancer-for-nginx-and-mongrel">Fair Proxy Balancer</a>' plugin (<a href="http://forum.engineyard.com/forums/6/topics/36">EngineYard is rumored to be running it</a>). Having said that, HAProxy is more robust, gives you more knobs to tweak, and features a <a href="http://demo.1wt.eu/">great admin interface</a>!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=XevYsH"><img src="http://feeds.feedburner.com/~f/igvita?i=XevYsH" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=rzBUyh"><img src="http://feeds.feedburner.com/~f/igvita?i=rzBUyh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=aDwH0h"><img src="http://feeds.feedburner.com/~f/igvita?i=aDwH0h" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=Ift07h"><img src="http://feeds.feedburner.com/~f/igvita?i=Ift07h" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=mLRq6h"><img src="http://feeds.feedburner.com/~f/igvita?i=mLRq6h" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/289383077" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/05/13/load-balancing-qos-with-haproxy/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F05%2F13%2Fload-balancing-qos-with-haproxy%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/05/13/load-balancing-qos-with-haproxy/</feedburner:origLink></item>
		<item>
		<title>MySQL Conf - Memcached Internals</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/275502600/</link>
		<comments>http://www.igvita.com/2008/04/22/mysql-conf-memcached-internals/#comments</comments>
		<pubDate>Tue, 22 Apr 2008 16:18:50 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Architecture]]></category>

		<category><![CDATA[cache]]></category>

		<category><![CDATA[memcached]]></category>

		<category><![CDATA[mysqlconf]]></category>

		<category><![CDATA[mysqluc08]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/04/22/mysql-conf-memcached-internals/</guid>
		<description><![CDATA[Brian Aker and Alan Kasindorf gave a great talk on Memcached - every developer's favorite caching layer - at MySQL User Conference earlier last week. The slides are available online, and they're well worth a bookmark. Brian and Alan promised to continue updating the deck as they hone out their presentation at OSCON and other [...]]]></description>
			<content:encoded><![CDATA[<p><img align="left" src="http://www.igvita.com/blog/posts/04-08/cache.png" style="margin: 0pt 1em 0pt 0pt;"/><a href="http://krow.net/">Brian Aker</a> and <a href="http://dormando.livejournal.com/">Alan Kasindorf</a> gave a great talk on Memcached - every developer's favorite caching layer - at <a href="http://en.oreilly.com/mysql2008/public/schedule/detail/1627">MySQL User Conference</a> earlier last week. The <a href="http://download.tangent.org/talks/Memcached%20Study.pdf">slides are available online</a>, and they're well worth a bookmark. Brian and Alan promised to continue updating the deck as they hone out their presentation at OSCON and other events. In fact, their next iteration will include the <a href="http://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/">Nginx integration trick</a>, and new and improved section on consistent hashing. In other words, check back frequently.</p>
<h4><strong>Memcached Best Practices</strong></h4>
<p>At its core, Memcached is a high-performance, distributed caching system. It is application neutral, and is currently used on many large scale web sites such as Facebook (2TB of cache, circa Q1 2008), LiveJournal, Mixi, Hi5, etc. However, it is also an extremely simple piece of software: all of the logic is client-side, there is no security model, failover, backup mechanisms, or persistence (albeit the last one is in the roadmap). But that hasn't stopped the developers from deploying it in all kinds of environments, and here are a few best practices suggested by Brian: </p>
<blockquote><ol>
<li>Don't think row-level (database) caching, think complex objects</li>
<li>Don't run memcached on your database server, give your database all the memory it can get</li>
<li>Don't obsess about TCP latency - localhost TCP/IP is optimized down to an in-memory copy</li>
<li>Think multi-get - run things in parallel whenever you can</li>
<li>Not all memcached client libraries are made equal, do some research on yours - hint, use <a href="http://hg.tangent.org/libmemcached/">Brians</a>.</li>
</ol>
</blockquote>
<h4><strong>Slab Allocator - Heart of Memcached</strong></h4>
<p>The heart of Memcached is in its memory slab allocator. A little daunting at first sight, it is actually a very elegant solution once you understand the motivation and the tradeoffs of its architecture:</p>
<blockquote><ul>
<li>Size of maximum allocated memory to Memcached is only limited by the architecture (32/64-bit)</li>
<li>The key size is limited to 250 bytes, the data (value) size is limited to 1mb</li>
<li>On bootup, Memcached grabs the memory and holds on to it - wasted memory at cost of performance</li>
<li>Allocated memory is split into variable sized buckets by the slab allocator</li>
<li>Default slab allocator will create 32-39 buckets for objects up to 1mb in size</li>
<li>You can customize the page size at compile time, and slab sizes on startup</li>
<li>Each stored objects gets stored in a closest-size bucket - yes, memory is wasted</li>
<li>Fragmentation can be a problem - either customize slab sizes, or evict/flush your cache every so often</li>
<li>If there is unused memory in a different slab class, that memory will be re-allocated, if required</li>
<li>To guarantee no-paging, <a href="http://kerneltrap.org/node/3000">disable swap on your OS</a> - practically, just keep it tiny, as to avoid disasters</li>
</ul>
</blockquote>
<h4><strong>Memory Management</strong></h4>
<p>The memory is managed via a <a href="http://en.wikipedia.org/wiki/LRU">Least Recently Used</a> (LRU) algorithm:</p>
<blockquote><ul>
<li>Each slab class has its own LRU - evict target depends on the size of the object</li>
<li>Expiration timestamps are checked once every second - minimum lifespan is 1 second</li>
<li>Objects marked for deletion are handled asynchronously - checked and evicted once every 5 seconds</li>
<li>Inconsistency between the two timers listed above can result in sub-optimal eviction policy</li>
<li>LRU can be completely disabled - do it at your own risk</li>
</ul>
</blockquote>
<h4><strong>Best Practices: Invalidations and Expiry</strong></h4>
<p>Memcached does not provide any mechanisms for deleting a set of associated keys (object, name, etc.). For good or for worse, you could implement this functionality yourself with the help of <em>prepend</em> and <em>append</em> commands, however, be careful with the 1mb limit! A much cleaner way to handle this situation is to forgo the invalidation process all together:</p>
<blockquote>
<ul>
<li>Instead of invalidating your data, expire it whenever you can - memcached will do all the work</li>
<li>Generate smart keys - ex. on update, <a href="http://blog.leetsoft.com/2007/5/22/the-secret-to-memcached">increment a version number</a>, which will become part of the key</li>
<li>For bonus points, store the version number in memcached - call it generation</li>
<li>The latter will be added to Memcached soon - as soon as Brian gets around to it</li>
</ul>
</blockquote>
<h4><strong>Roadmap and Future Ahead</strong></h4>
<p>Memcached is a force to be reckoned with already, and the roadmap is only going to solidify this position. Amongst the big objectives:</p>
<blockquote>
<ul>
<li>Binary protocol is in the works</li>
<li>Support for generations - as described in paragraph above</li>
<li>Multi-engine support: char based, durable (persistence!), queue</li>
<li>Facebook has overhauled the core to be highly-threaded, and is expected to contribute the changes</li>
</ul>
</blockquote>
<p>Kudos to Brian and Alan for a great presentation! Don't forget to bookmark the slides and check back every so often, as they will be updated with time to describe best practices, common mistakes, and the roadmap ahead.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=1S2JpVG"><img src="http://feeds.feedburner.com/~f/igvita?i=1S2JpVG" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=nfL5jrg"><img src="http://feeds.feedburner.com/~f/igvita?i=nfL5jrg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=9MSMkfg"><img src="http://feeds.feedburner.com/~f/igvita?i=9MSMkfg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=cuChHpg"><img src="http://feeds.feedburner.com/~f/igvita?i=cuChHpg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=L9pcncg"><img src="http://feeds.feedburner.com/~f/igvita?i=L9pcncg" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/275502600" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/04/22/mysql-conf-memcached-internals/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F04%2F22%2Fmysql-conf-memcached-internals%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/04/22/mysql-conf-memcached-internals/</feedburner:origLink></item>
		<item>
		<title>Custom PuTTY Color Themes</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/270023333/</link>
		<comments>http://www.igvita.com/2008/04/14/custom-putty-color-themes/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 13:59:35 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Projects]]></category>

		<category><![CDATA[putty]]></category>

		<category><![CDATA[ssh]]></category>

		<category><![CDATA[theme]]></category>

		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/04/14/custom-putty-color-themes/</guid>
		<description><![CDATA[I can't help myself, I seem to spend inordinate amounts of my time working inside a remote SSH tunnel on a daily basis. And nothing is worse than trying to decipher the default dark-blue/green/red colors against a black background in PuTTY. Coming from SecureCRT, which has much better defaults, I set out on a hunt [...]]]></description>
			<content:encoded><![CDATA[<p>I can't help myself, I seem to spend inordinate amounts of my time working inside a remote SSH tunnel on a daily basis. And nothing is worse than trying to decipher the default dark-blue/green/red colors against a black background in PuTTY. Coming from <a href="http://www.vandyke.com/products/securecrt/">SecureCRT</a>, which has much better defaults, I set out on a hunt for good PuTTY alternative, and voila:</p>
<p align="center"><img height="194" style="border:1px solid #999; padding:1px;" alt="putty-terminals" src="/posts/04-08/putty-terminals.png" width="567" align="center" border="0" /></p>
<h4><strong>Customizing color schemes in PuTTY</strong></h4>
<p>It appears that the best way to approach this problem is to enable ANSI color support and customize from there. Thankfully, <a href="http://www.darkrune.org/blog/?p=213">Steve T.</a> has documented <a href="http://www.vim.org/tips/tip.php?tip_id=1291">his findings</a>, which enabled me to easily customize a few themes of my own. From left to right, in the preview above: default theme, light, desert (with a few improvements).</p>
<p><div class='download-link'>
							<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/igvita-light.reg'><img alt='Download' class='leftalign' src='http://www.igvita.com/wp-content/plugins/dBeautifier/icons/downloads.png' /></a>
							<h4>
								<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/igvita-light.reg'>igvita-light.reg (Light-er default theme)</a>
							</h4><p>Downloads: 2340 File Size: 14.2 KB </p>
						</div><br />
<div class='download-link'>
							<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/igvita-desert.reg'><img alt='Download' class='leftalign' src='http://www.igvita.com/wp-content/plugins/dBeautifier/icons/downloads.png' /></a>
							<h4>
								<a href='http://www.igvita.com/download.php?file=http://www.igvita.com/downloads/igvita-desert.reg'>igvita-desert.reg (Desert theme)</a>
							</h4><p>Downloads: 2826 File Size: 14.3 KB </p>
						</div></p>
<p>To get started, download the registry file, run it, reload your PuTTY terminal, enjoy! Tip: Vista users, make sure you're using the new 'Consolas' font as your default.</p>
<h4><strong>Nice upgrade: PuTTY Tray</strong></h4>
<p>While hunting for colors, I also came across an awesome enhancement: <a href="http://www.xs4all.nl/~whaa/putty/">PuTTY Tray</a>, which I highly recommend.  Amongst many other things, it offers auto-reconnect, session persistence in files, 'always on top', URL hyperlinking, and the list goes on. And the best part is, for all intents and purposes, it's the same PuTTY terminal!</p>
<p>What's your favorite PuTTY tip or trick?</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=gmo2DmG"><img src="http://feeds.feedburner.com/~f/igvita?i=gmo2DmG" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=yicGvag"><img src="http://feeds.feedburner.com/~f/igvita?i=yicGvag" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=2HLz6Dg"><img src="http://feeds.feedburner.com/~f/igvita?i=2HLz6Dg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=HYhudKg"><img src="http://feeds.feedburner.com/~f/igvita?i=HYhudKg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=WLSq02g"><img src="http://feeds.feedburner.com/~f/igvita?i=WLSq02g" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/270023333" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/04/14/custom-putty-color-themes/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F04%2F14%2Fcustom-putty-color-themes%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/04/14/custom-putty-color-themes/</feedburner:origLink></item>
		<item>
		<title>Agile Release &amp; Testing Procedures</title>
		<link>http://feeds.feedburner.com/~r/igvita/~3/265581079/</link>
		<comments>http://www.igvita.com/2008/04/07/agile-release-testing-procedures/#comments</comments>
		<pubDate>Mon, 07 Apr 2008 10:51:53 +0000</pubDate>
		<dc:creator>Ilya Grigorik</dc:creator>
		
		<category><![CDATA[Agile Methods]]></category>

		<category><![CDATA[aiderss]]></category>

		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.igvita.com/2008/04/07/agile-release-testing-procedures/</guid>
		<description><![CDATA[ You've scored yourself an amazing team, you've all wholesale committed to some form of agile development model (scrum, crystal, fdd, etc.) and now you're in the thick of it - with a release coming up - and the question is: how do you test, what do you test, when do you stop? 
The underlying [...]]]></description>
			<content:encoded><![CDATA[<p><img align="left" style="margin: 0pt 1em 0pt 0pt;" src="http://www.igvita.com/blog/posts/04-08/testing.png"/> You've scored yourself an amazing team, you've all wholesale committed to some form of agile development model (<a href="http://en.wikipedia.org/wiki/Scrum_(development)">scrum</a>, <a href="http://en.wikipedia.org/wiki/Crystal_Clear_(software_development)">crystal</a>, <a href="http://en.wikipedia.org/wiki/Feature_Driven_Development">fdd</a>, etc.) and now you're in the thick of it - with a release coming up - and the question is: <em>how do you test, what do you test, when do you stop?</em> </p>
<p>The underlying tenets of agile - short iterations, quick releases, faster feedback loops - create an underlying tension with many of the 'traditional' testing requirements. A quick google search for 'types of software testing' brings up several dozen concepts, many of which are nothing short of unrealistic given typical one/two week team iteration. Of course, value of any practice depends on its context, which is another way of saying: there are good practices in context, but there are no best practices. Hence, let's set the context: you're a small web development team (2-7 people), working on a live project (you have customers), with expectation of delivering a functional slice of your backlog every two weeks.</p>
<h4><strong>Flickr, Friendfeed, and others...</strong></h4>
<p>Good software testing is a challenging process. Every project follows some logical path from under the developers fingers and into a production environment - granted, sometimes this process can be as simple as editing a file live (we're all guilty of it at times). In their early days, Flickr ran with pseudo <a href="http://magpiebrain.com/blog/2005/10/17/web-20-needs-testing/">30-minute release cycles</a>, more recently, Friendfeed is showing several <a href="http://changelog.friendfeed.com/">1-2 day release iterations</a>. Have either fully automated their testing and staging environments? I doubt it. In fact, Cal Henderson's remarks about the early days of Flickr clearly show lack of such infrastructure, and yet, Flickr has always been known for their excellent user experience.</p>
<h4><strong>Discovering the formula</strong></h4>
<p><img align="left" style="margin: 0pt 1em 0pt 0pt;" src="http://www.igvita.com/blog/posts/04-08/testing-cartoon.png"/>How far do you go? Unit testing can be derived from test driven development, integration testing requires a staging environment, user acceptance is the logical conclusion in Scrum, and what about the remainder? Given the scarce resources - time, people, and money - most web startups seem to forgo, or pick and choose from the remainder. Perhaps this is a sign of immaturity and we're <a href="http://searchsoftwarequality.techtarget.com/news/article/0,289142,sid92_gci1260130,00.html">unconsciously hurting ourselves</a>, or maybe, the old model simply does not recognize the modern requirements.</p>
<p>Intrigued by this question, I've recently engaged in a number of online and offline conversations with team leads, and fellow entrepreneurs. The end result? A full spectrum of testing environments, including a few cases of complete lack of thereof - all the while, the projects are high-profile, high-traffic websites. For obvious reasons, we'll let the names be anonymous, but this raises an interesting question:</p>
<blockquote><p><em>How do <strong>you</strong> test, what do <strong>you</strong> test, when do <strong>you</strong> (or your team) stop? Phrased differently, what are your release procedures?</em></p></blockquote>
<p>Would love to hear your feedback, war stories, and rumors. Once the dust settles, I'll aggregate and report the results.</p>
<p>P.S. Testing is not assurance of quality.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/igvita?a=U9xSJFG"><img src="http://feeds.feedburner.com/~f/igvita?i=U9xSJFG" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=kgLWSmg"><img src="http://feeds.feedburner.com/~f/igvita?i=kgLWSmg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=LHAx0jg"><img src="http://feeds.feedburner.com/~f/igvita?i=LHAx0jg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=9gVW3fg"><img src="http://feeds.feedburner.com/~f/igvita?i=9gVW3fg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/igvita?a=xTdZoVg"><img src="http://feeds.feedburner.com/~f/igvita?i=xTdZoVg" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/igvita/~4/265581079" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.igvita.com/2008/04/07/agile-release-testing-procedures/feed/</wfw:commentRss>
		<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=igvita&amp;itemurl=http%3A%2F%2Fwww.igvita.com%2F2008%2F04%2F07%2Fagile-release-testing-procedures%2F</feedburner:awareness><feedburner:origLink>http://www.igvita.com/2008/04/07/agile-release-testing-procedures/</feedburner:origLink></item>
	<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetFeedData?uri=igvita</feedburner:awareness></channel>
</rss>
