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

<channel>
	<title>Coffee Powered &#187; Ruby</title>
	<atom:link href="http://www.coffeepowered.net/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.coffeepowered.net</link>
	<description>code and content</description>
	<lastBuildDate>Sun, 05 Sep 2010 20:38:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Debugging memory leaks in Ruby with GDB, round 2.</title>
		<link>http://www.coffeepowered.net/2010/08/23/debugging-memory-leaks-in-ruby-with-gdb-round-2/</link>
		<comments>http://www.coffeepowered.net/2010/08/23/debugging-memory-leaks-in-ruby-with-gdb-round-2/#comments</comments>
		<pubDate>Mon, 23 Aug 2010 23:02:22 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[gdb]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=310</guid>
		<description><![CDATA[In part 1, I described how I located leaky Sets in MongoMapper by diffing the Ruby ObjectSpace with GDB. Today, I&#8217;m going to show you how to solve the problems that those sorts of diffs can reveal. In today&#8217;s example, we&#8217;re tracking leaky sets. In particular, a set is holding onto class references. We are [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.coffeepowered.net/2010/08/23/mongomapper-development-mode-and-memory-leaks/">part 1</a>, I described how I located leaky <code>Set</code>s in MongoMapper by diffing the Ruby ObjectSpace with GDB. Today, I&#8217;m going to show you how to solve the problems that those sorts of diffs can reveal. In today&#8217;s example, we&#8217;re tracking leaky sets. In particular, a set is holding onto class references. We are going to:</p>
<ol>
<li>Set up object creation tracking on the Set class</li>
<li>Find the leaky instance of our set using GDB</li>
<li>Locate what code created that Set instance</li>
</ol>
<p><span id="more-310"></span><br />
First things first. Check out Sean Bradly&#8217;s <a href="http://drunkhobo.com/~sean/gctrack.rb.html">GCTrack</a> module. I&#8217;m using a modified version of it to include object IDs in the tracker struct, so that we can perform reverse-lookups on an instance.</p>
<pre class="brush: ruby;">
# Sean Bradly (rhythmx at gmail) - 2010
# Modified by Chris Heald (cheald@gmail.com) - August 2010
module GCTrack
  # Class to track an object's lifecycle and where it was created
  class Tracepoint &lt; Struct.new(:num, :call, :insp, :id)
    include Comparable
    # make it so the obj.num works as a simple key
    def &lt;=&gt;(obj)
      if obj.class &lt;= self.class
        self.num &lt;=&gt; obj.num
      else
        self.num &lt;=&gt; obj
      end
    end
  end

  def self.included(klass)

    # Hook initialize to track this object
    klass.class_eval do
      alias_method :old_init, :initialize

      def initialize(*args)
        # Call original init
        old_init(*args)
        # trace creation and setup finalizer callback
        final_proc = self.class.gct_setup_finalizer(self, caller, inspect)
        # define the finalizer
        ObjectSpace.define_finalizer(self, final_proc)
      end
    end

    # Add some metaclass foo to track all the objects.
    # You cant track in an instance w/o creating circular
    # references and breaking Ruby's GC

    (
    class &lt;&lt; klass;
      self;
    end).class_eval do
      def gct_setup_finalizer(obj, caller, insp)
        # create/log a tracepoint for this object
        num = gct_objnum
        tpoint = Tracepoint.new(num, caller, insp, obj.object_id)
        gct_add(tpoint)
        # call option init cb
        if self.respond_to?(:created)
          self.send(:created, tpoint)
        end
        obj = nil # don't let the proc track a ref to 'obj'
        # this callback happens at GC time
        final_proc = Proc.new do
          gct_del(tpoint)
          # call optional final cb
          if self.respond_to?(:deleted)
            self.send(:deleted, tpoint)
          end
        end
      end

      def gct_objnum
        @num ||= -1
        @num  +=  1
      end

      def gct_addlog
        @addlog ||= []
      end

      def gct_dellog
        @dellog ||= []
      end

      def gct_add(num)
        gct_addlog &lt;&lt; num
      end

      def gct_del(num)
        gct_dellog &lt;&lt; num
      end

      def gct_active
        gct_addlog - gct_dellog
      end

      def gct_origin(id)
        x = gct_addlog.select {|g| g.id == id }.first
        x.nil? ? nil : x.call.join(&quot;\n&quot;)
      end

      def gct_orphan_report
        # Get the leaked objects
        rpt     = &quot;&quot;
        leaked  = gct_active
        callers = leaked.map { |o| o.call }.sort.uniq
        # Iterate over source lines that have leaked objs
        callers.each do |calla|
          leaked_here = leaked.find_all { |o| o.call == calla }
          rpt &lt;&lt; &quot;==== #{leaked_here.size} leaked objects from:\n\n&quot;
          calla.each { |l| rpt &lt;&lt; &quot;    #{l}\n&quot; }
          rpt &lt;&lt; &quot;\n&quot;
          rpt &lt;&lt; &quot;    == object data:\n\n&quot;

          leaked_here.each do |o|
            rpt &lt;&lt; &quot;    num: #{o.num}, inspect: #{o.insp}\n&quot;
          end
          rpt &lt;&lt; &quot;\n&quot;
        end
        rpt
      end

    end
  end
end
</pre>
<p>Additionally, you&#8217;ll want to patch the object you&#8217;re interested in tracking.</p>
<pre class="brush: ruby;">
class Set
  include GCTrack
end
</pre>
<p>You&#8217;ll want to include both of those at the top of your config.rb, before your initializer block. If you&#8217;re tracking an object defined in your Rails app, just include GCTrack in the object definition, rather than in a monkeypatch.</p>
<p>Next, you need to be sure that you have your GDB macros set up properly. /root/.gdbinit should have the following:</p>
<pre class="brush: bash;">
define eval
  call(rb_p(rb_eval_string_protect($arg0,(int*)0)))
end

define redirect_stdout
  call rb_eval_string(&quot;$_old_stdout, $stdout = $stdout, File.open('/tmp/ruby-debug.' + Process.pid.to_s, 'a'); $stdout.sync = true&quot;)
end
</pre>
<p>(re)start your application, hit the leaky action a few times, and find its PID using <code>ps ax</code> or <code>top</code>. Once you have that, attach to the process with gdb, redirect your process&#8217;s stdout to the tmp file with <code>redirect_stdout</code> and dump all <code>Set</code>s in your object space.</p>
<pre class="brush: bash;">
(gdb) attach 12345
(gdb) redirect_stdout
$8 = 2
(gdb) eval &quot;GC.start&quot;
(gdb) eval &quot;ObjectSpace.each_object {|o| puts \&quot;#{o.class.name}, #{o.inspect} -- #{o.object_id}\&quot; if o.is_a?(Set) }; puts '----'&quot;
</pre>
<p>Now that we have that, let&#8217;s look at the tmp file, and locate the leaked set instance.</p>
<pre class="brush: plain;">
Set, #&lt;Set: {Achievement, Achievement, EmbeddedComment, Achievement, EmbeddedComment, EmbeddedComment}&gt; -- 78376680
</pre>
<p>There, at the end, is our object ID. Now back over to gdb.</p>
<pre class="brush: bash;">
(gdb) eval &quot;puts Set.gct_addlog.select {|g| g.id == 78376680}.first.call.join(\&quot;\n\&quot;)&quot;
</pre>
<p>Your tmp file should now have a stack trace for that object&#8217;s allocation now. Track it down and beat it into submission.</p>
<pre class="brush: plain;">
/opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/mongo_mapper-0.8.3/lib/mongo_mapper/support/descendant_appends.rb:15:in `new'
</pre>
<p>You can do this for just about any object you&#8217;d like. Just mix in your GCTrack and easily find where in code a particular instance of an object was created. Just like that, debugging memory leaks goes from hunting guppies in the Atlantic to shooting fish in a barrel.</p>
<p>Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2010/08/23/debugging-memory-leaks-in-ruby-with-gdb-round-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoMapper, Development Mode, and Memory Leaks</title>
		<link>http://www.coffeepowered.net/2010/08/23/mongomapper-development-mode-and-memory-leaks/</link>
		<comments>http://www.coffeepowered.net/2010/08/23/mongomapper-development-mode-and-memory-leaks/#comments</comments>
		<pubDate>Mon, 23 Aug 2010 11:15:24 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[fixes]]></category>
		<category><![CDATA[gdb]]></category>
		<category><![CDATA[memory leak]]></category>
		<category><![CDATA[mongomapper]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=308</guid>
		<description><![CDATA[If you&#8217;ve worked with MongoMapper for a while, you&#8217;ve probably noticed that in complex apps, there are horrific memory leaks in development that magically disappear in production mode. While this is all well and good, and it&#8217;s rather handy that things Just Work in production, don&#8217;t you wish you didn&#8217;t have to restart your app [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve worked with MongoMapper for a while, you&#8217;ve probably noticed that in complex apps, there are horrific memory leaks in development that magically disappear in production mode. While this is all well and good, and it&#8217;s rather handy that things Just Work in production, don&#8217;t you wish you didn&#8217;t have to restart your app server every 15 requests in development?</p>
<p>I set out to track down the cause tonight, and have both fixed the problem and gotten some handy experience debugging Rails apps with gdb.</p>
<p><span id="more-308"></span></p>
<h2>The Solution</h2>
<p>First off, if you just want the fix, here it is. You probably have a middleware to clear your identity maps already. We&#8217;re just going to modify that. In my case, it&#8217;s <code>lib/mongo_mapper/per_request_identity_map_clear.rb</code>.</p>
<pre class="brush: ruby;">
module MongoMapper
  class PerRequestMapClear
    def initialize(app)
      @app = app
    end

    def call(env)
      if Rails.configuration.cache_classes
        MongoMapper::Plugins::IdentityMap.clear
      else
        MongoMapper::Document.descendants.each do |m|
          m.descendants.clear if m.respond_to? :descendants
        end
        MongoMapper::Document.descendants.clear
        MongoMapper::EmbeddedDocument.descendants.clear
        MongoMapper::Plugins::IdentityMap.clear
        MongoMapper::Plugins::IdentityMap.models.clear
      end
      @app.call(env)
    end
  end
end
</pre>
<p>In particular, these two lines:</p>
<pre class="brush: ruby;">
  MongoMapper::Document.descendants.clear
  MongoMapper::Plugins::IdentityMap.models.clear
</pre>
<p>Make sure you get that into your middleware stack and all your MongoMapper memory leaking issues will magically disappear.</p>
<h2>The Problem</h2>
<p>You see, MongoMapper is doing some <em>dag-nasty evil stuff</em> with class references. Namely, it&#8217;s holding onto them in class variables that don&#8217;t get reloaded per-request in Rails. Simply:</p>
<ol>
<li>Rails loads your <code>User</code> model. This loads up a ton of Validations, MongoMapper::Keys, procs, and whatever else you have in your model definition. It&#8217;s not really light. That&#8217;s okay because we load it only once in production.</li>
<li>This is a <code>MongoMapper::Document</code>, which causes User (the class reference) to be inserted into the <code>MongoMapper::Document.descendants</code> class attribute, which happens to be a Set object.</li>
<li>Next time you refresh a page, Rails re-loads your <em>User</em> model. This creates a <em>new and separate User class reference</em>. It does not replace the previous <em>User</em> class reference. It is not equal to your previous User class reference. They are, as far as Ruby cares, separate objects.</li>
<li>MongoMapper happily sticks that class reference into its <code>descendants</code> class attribute. You now have two separate copies of User. Since MongoMapper is holding onto a reference to your old User class, Ruby can never garbage collect it. The old User class and all of its huge cascading chain of referenced objects are now &#8220;leaked&#8221;.</li>
<li>Your memory usage is increasing by 4mb per request now.</li>
</ol>
<p>I had app instances reaching nearly 1GB of RAM usage after light testing. I finally noticed it when my development machine kicked into swap and actions that took 80ms to run were taking 8000ms to run. Hm. That might be a problem!</p>
<h2>Debugging leaks with GDB</h2>
<p>GDB is an amazing tool. With a few macros, you can make hacking around in a live Ruby instance pretty painless. Crack open your <code>/root/.gdbinit</code> file and add a few macros:</p>
<pre class="brush: bash;">
define eval
  call(rb_p(rb_eval_string_protect($arg0,(int*)0)))
end

define redirect_stdout
  call rb_eval_string(&quot;$_old_stdout, $stdout = $stdout, File.open('/tmp/ruby-debug.' + Process.pid.to_s, 'a'); $stdout.sync = true&quot;)
end
</pre>
<p>Now, we&#8217;re going to attach to your running Ruby process. This needs to be done as root.</p>
<pre class="brush: bash;">
[root@polaris ~]# gdb
(gdb) attach 12019
(gdb) redirect_stdout
(gdb) eval &quot;ObjectSpace.each_object {|o| puts \&quot;#{o.class.name}, #{o.inspect} -- #{o.object_id}\&quot; unless o.is_a?(String) }; puts '----'&quot;
</pre>
<p>This will effectively dump all non-String objects in the attached Ruby process to <code>tmp/ruby-debug.12019</code>. This takes a little bit, but it lets you come up with some handy data for parsing later.</p>
<p>To get data we can compare, we&#8217;ll need to dump the environment for multiple requests:</p>
<pre class="brush: bash;">
[root@polaris ~]# gdb
(gdb) attach 12019
(gdb) redirect_stdout
(gdb) eval &quot;GC.start&quot;
(gdb) eval &quot;ObjectSpace.each_object {|o| puts \&quot;#{o.class.name}, #{o.inspect} -- #{o.object_id}\&quot; unless o.is_a?(String) }; puts '----'&quot;
(gdb) detach

(run some requests)

(gdb) attach 12019
(gdb) redirect_stdout
(gdb) eval &quot;GC.start&quot;
(gdb) eval &quot;ObjectSpace.each_object {|o| puts \&quot;#{o.class.name}, #{o.inspect} -- #{o.object_id}\&quot; unless o.is_a?(String) }; puts '----'&quot;
(gdb) detach
</pre>
<p>At this point, you&#8217;ll have two ObjectSpace dumps in your temp file. For my purposes, I hacked up a quick little script to parse those dumps, and to output all objects that were not present in both dumps. Since I&#8217;m invoking GC.start, in theory, this should help me find my leaked objects.</p>
<pre class="brush: ruby;">
runs = [[]]
open(ARGV[0]).each do |line|
  if line == &quot;----\n&quot; then
    runs &lt;&lt; []
  elsif line.match &quot;--&quot; then
    runs.last &lt;&lt; line.strip
  end
end

diff = []
runs.each do |run|
  diff = (diff - run) | (run - diff)
end
diff.sort.map {|d| puts d }</pre>
<p>Not very pretty, but it does the job. Just a quick invocation to <code>ruby find_leaked.rb /tmp/ruby-debug.12019 > leaked</code> (well, not that quick, it took a minute to run) and I effectively had an ObjectSpace diff I could pore through.</p>
<p>There&#8217;s a lot of stuff in there. In particular, you&#8217;re going to notice that you have a LOT of Array, Hash, and MatchData objects (perhaps potential optimization points for future Rails releases?). While we may be interested in those, try to cull out the things that obviously aren&#8217;t a problem just for readability&#8217;s sake.</p>
<p>I pored through the diff looking for things related to MongoMapper or my models. After not too long, I came across these lines:</p>
<pre class="brush: ruby;">
Set, #&lt;Set: {Achievement, EmbeddedComment, Achievement, EmbeddedComment, EmbeddedComment, Achievement, Achievement, EmbeddedComment, EmbeddedComment, Achievement, EmbeddedComment, EmbeddedComment, Achievement, Achievement, Achievement, EmbeddedComment, EmbeddedComment, Achievement}&gt; -- 92034680
Set, #&lt;Set: {Achievement, EmbeddedComment, Achievement, EmbeddedComment, EmbeddedComment, Achievement, Achievement, EmbeddedComment, EmbeddedComment, Achievement, EmbeddedComment, EmbeddedComment, Achievement, Achievement, EmbeddedComment, Achievement, Achievement, EmbeddedComment, EmbeddedComment, Achievement}&gt; -- 92034680
</pre>
<p>Whoa there. What? Why do I have Sets with multiple references to <code>Achievement</code> and <code>EmbeddedComment</code>? That doesn&#8217;t smell right. I suspect the problem lies in MongoMapper, so let&#8217;s grep the MongoMapper codebase for Set.</p>
<pre class="brush: bash;">
[chris@polaris lib]$ grep Set * -R
mongo_mapper/plugins/identity_map.rb:        @models ||= Set.new
mongo_mapper/plugins/modifiers.rb:          modifier_update('$addToSet', args)
mongo_mapper/plugins/protected.rb:          self.write_inheritable_attribute(:attr_protected, Set.new(attrs) + (protected_attributes || []))
mongo_mapper/plugins/accessible.rb:          self.write_inheritable_attribute(:attr_accessible, Set.new(attrs) + (accessible_attributes || []))
mongo_mapper/support/descendant_appends.rb:        @descendants ||= Set.new
mongo_mapper/connection.rb:      raise 'Set config before connecting. MongoMapper.config = {...}' unless defined?(@@config)
mongo_mapper/connection.rb:      raise 'Set config before connecting. MongoMapper.config = {...}' if config.blank?
mongo_mapper/extensions/set.rb:    module Set
mongo_mapper/extensions/set.rb:class Set
mongo_mapper/extensions/set.rb:  extend MongoMapper::Extensions::Set
</pre>
<p>Great, we have a hit list to look through. IdentityMap is worth looking at; a new set is created there, and its naming indicates that it&#8217;s for holding models, probably model references (it is). <code>mongo_mapper/support/descendant_appends.rb</code> is much the same deal. We can ignore <code>mongo_mapper/plugins/accessible.rb</code> since we can guess that the <code>attrs</code> being passed are symbols, rather than those class references we saw in the ObjectSpace diff.</p>
<p>Let&#8217;s crack open <code>descendant_appends.rb</code></p>
<pre class="brush: ruby;">
module MongoMapper
  module Support
    module DescendantAppends
      def included(model)
        extra_extensions.each { |extension| model.extend(extension) }
        extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
        descendants &lt;&lt; model
      end

      # @api public
      def descendants
        @descendants ||= Set.new
      end
</pre>
<p>Oh dear. And there it is. Every time <code>MongoMapper::Support::DescendantAppends</code> is included in a model (which is via <code>MongoMapper::Document</code> and <code>MongoMapper:EmbeddedDocument</code>), <em>a reference to the including class</em> is stored in a <em>class variable</em>.</p>
<p>Since we know that Rails reloads models per-request in development mode, and we know that each copy of a model&#8217;s class is not considered equivalent to the other copies of that class, it&#8217;s easy to see what happens here: We end up with sets like in our object dump, with however many orphaned old copies of our models, and all their various and sundry associated models.</p>
<p>And so, we arrive at our solution. By clearing the <em>descendants</em> set on every request where we are reloading our models, we ensure that there are not references to old copies of models left hanging around leaking memory.</p>
<p>My development instances are now running solid at 68mb apiece, rather than 1gb apiece. As you can imagine, the difference in response speed (and thus, productivity) is substantial.</p>
<p>Hope this helps. Have fun with gdb &#8211; it&#8217;s an obscenely powerful tool, and used properly, can give you a purely nutty amount of information which can be invaluable in tracking down memory leaks and related problems.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2010/08/23/mongomapper-development-mode-and-memory-leaks/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WillPaginate and custom paging.</title>
		<link>http://www.coffeepowered.net/2010/08/07/willpaginate-and-custom-paging/</link>
		<comments>http://www.coffeepowered.net/2010/08/07/willpaginate-and-custom-paging/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 22:57:19 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[will_paginate]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=300</guid>
		<description><![CDATA[will_paginate is the de facto Rails paging plugin, and with good reason &#8211; it&#8217;s solid, fast, and reliable. Everyone I know uses it, but a lot of people don&#8217;t use it to its full power. I recently discovered some very cool functionality it includes &#8211; the WillPaginate::Collection class can be used as a custom paginator [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wiki.github.com/mislav/will_paginate/">will_paginate</a> is the de facto Rails paging plugin, and with good reason &#8211; it&#8217;s solid, fast, and reliable. Everyone I know uses it, but a lot of people don&#8217;t use it to its full power.</p>
<p>I recently discovered some <em>very</em> cool functionality it includes &#8211; the <code>WillPaginate::Collection</code> class can be used as a custom paginator for effectively any enumerable collection. It&#8217;s very simple, too. I recently used it to build pages of the most popular tags on posts in my database. My data store is MongoDB, and I&#8217;m fetching an array consisting of two-element arrays, <code>[tag, tag_count]</code>. To use will_paginate&#8217;s functionality with this, I just use the following:</p>
<pre class="brush: ruby;">
tags = Post.tag_counts(nil, {:sort =&gt; [&quot;value&quot;, &quot;descending&quot;]}) # Return an array of tag/count pairs. Custom function, so it can't leverage the finder on Post.
@topics = WillPaginate::Collection.create(current_page, 20, tags.length) do |pager|
	pager.replace(tags.slice(pager.offset, pager.offset + pager.per_page))
end
</pre>
<p><code>current_page</code> is a helper that derives the current page from the request parameters. The rest of it is self-explanitory. I can now use <code>@topics</code> in my page just as I&#8217;d use a paginated result set from the database.</p>
<pre class="brush: ruby;">
- @topics.each do |topic|
    # ...
=will_paginate @topics
</pre>
<p>Bam. Doesn&#8217;t get much easier than that. You can get exceptionally creative with it, too. Effectively, all you need to know is:</p>
<ul>
<li>WillPaginate::Collection#new takes 3 parameters: the current page, the per-page count, and optionally, the total number of entries.</li>
<li>The <code>pager</code> block variable exposes <code>offset</code> and <code>per_page</code> properties, prime for passing into a DB query or slicing an enumerable with</li>
<li>Call pager.replace(sub-array) with the current page&#8217;s set of elements.</li>
</ul>
<p>That&#8217;s literally all there is to it. Now you can have easy pagination on just about any collection you can conceive of. Let WillPaginate handle all the heavy lifting and such. If you&#8217;ve done enough pagination by hand, you&#8217;ll probably appreciate the easy beauty of this particular method.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2010/08/07/willpaginate-and-custom-paging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eight tips for getting the most out of your Rails app</title>
		<link>http://www.coffeepowered.net/2009/12/23/eight-tips-for-getting-the-most-out-of-your-rails-app/</link>
		<comments>http://www.coffeepowered.net/2009/12/23/eight-tips-for-getting-the-most-out-of-your-rails-app/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 10:04:57 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=205</guid>
		<description><![CDATA[Rails does an awful lot to optimize page generation, but there are a number of hacks, tweaks, and usage patterns you should be using to get the most out of your app. Configuration tweaks There&#8217;s a lot of the Rails stack that&#8217;s written in Ruby, which is great &#8211; it&#8217;s portable, it&#8217;s flexible, it works [...]]]></description>
			<content:encoded><![CDATA[<p>Rails does an awful lot to optimize page generation, but there are a number of hacks, tweaks, and usage patterns you should be using to get the most out of your app.</p>
<h2>Configuration tweaks</h2>
<p>There&#8217;s a lot of the Rails stack that&#8217;s written in Ruby, which is great &#8211; it&#8217;s portable, it&#8217;s flexible, it works out of the box. Unfortunately, for some things, this also means it&#8217;s slow. Other times, pieces of the framework aren&#8217;t implemented as optimally as they could be. What if you could improve your app&#8217;s performance just by installing a few gems and tweaking a few config parameters? Good news &#8211; it&#8217;s not hard.</p>
<h3>1. Replace REXML with LibXML</h3>
<p>By default, Rails uses a Ruby-native XML library called REXML. REXML is slow. REXML is very slow. REXML is personally responsible for me almost entirely giving up on Ruby due to a bad encounter with it in my first Ruby project. Fortunately, Rails provides a very easy way to avoid using REXML.</p>
<pre class="brush: ruby;">gem install libxml-ruby</pre>
<p>Then, in your app&#8217;s config/environment.rb</p>
<pre class="brush: ruby;">ActiveSupport::XmlMini.backend = 'LibXML'</pre>
<p>That&#8217;s it. Now, Rails will use the very lean, very fast libxml to parse XML documents, rather than the very fat, very slow REXML. If you&#8217;re doing feed parsing, Hash.from_xml, or anything of that nature, this will save you massive amounts of pain.</p>
<h3>2. <a href="http://slim-attributes.rubyforge.org/">slim_attributes</a></h3>
<p>If you&#8217;re using MySQL, there&#8217;s no reason why you shouldn&#8217;t be using slim_attributes.</p>
<blockquote><p>Slim Attributes boosts speed in Mysql/Rails ActiveRecord Models by avoiding instantiating Hashes for each result row, and lazily instantiating attributes as needed.</p></blockquote>
<p>Pretty self-explanatory. Rather than creating massive hashes of everything the DB gives you, slim_attributes causes ActiveRecord to only create ruby objects when you actually ask for them in code. This can reduce both your app&#8217;s memory usage and time spent on database queries. It&#8217;s not a massive increase, but given that it takes exactly one line of code to add to your project, there&#8217;s no reason not to use it.</p>
<h3>3. <a href="http://github.com/sdsykes/slim_scrooge">slim_scrooge</a></h3>
<p>From the developers of slim_attributes comes another drop-in database optimization.</p>
<blockquote><p>SlimScrooge is an optimization layer to ensure your application only fetches the database content needed to minimize wire traffic, excessive <span>SQL</span> queries and reduce conversion overheads to native Ruby types.</p>
<p>SlimScrooge implements inline query optimisation, automatically restricting the columns fetched based on what was used during previous passes through the same part of your code.</p></blockquote>
<p>Make your ORM work for you! By only fetching the content you need from your database, you reduce over-the-wire overhead, CPU overtime due to type conversion, and other such niceties. Again, just install the gem, require it in your project, and you&#8217;re off to the races.</p>
<h3>4. <a href="http://fast-xs.rubyforge.org/">fast_xs</a></h3>
<p>By default, string escaping in Rails happens in native Ruby code. This is slow. We don&#8217;t like slow. This is particularly prominent in areas like Builder::XmlMarkup, which you are using if you have any templates like <code>foo.xml.builder</code> lying around.</p>
<p>In modestly-sized document, this can result in pretty substantial slowdown in view construction. Rather than re-hashing what others have already done, I&#8217;ll point you at <a href="http://samsaffron.com/archive/2008/03/29/Speed+up+your+feed+generation+in+rails">Speed up your feed generation in Rails</a> for the long and short on it all. This can result in builder views running upwards of 10x as fast, and all you have to do is install the fast_xs gem &#8211; Rails will automatically detect and patch it in if it&#8217;s on the system.</p>
<h3>5. <a href="http://www.kuwata-lab.com/erubis/">Erubis</a></h3>
<p><img src="http://www.coffeepowered.net/wp-content/uploads/2009/12/erubis01.png" alt="Erubis benchmarks" title="Erubis benchmarks" width="351" height="262" class="alignright size-full wp-image-213" /> Erubis is an ERB implementation written in C, rather than in Ruby. As a result, it parses ERB templates very, very quickly. In fact, the Erubis benchmarks up it at upwards of 3x faster than the native ERB implementation. Installation is easy &#8211; just check the <a href="http://www.kuwata-lab.com/erubis/users-guide.05.html">using Erubis with Ruby on Rails guide</a> and you&#8217;re off to the races.</p>
<p>Do note that if you&#8217;re entirely using <a href="http://haml-lang.com/">Haml</a> or similar, Erubis won&#8217;t do much for you. Erubis is much faster than Haml, but Haml is much prettier than ERB. What you end up using is up to you!</p>
<h2>Reduce action runtimes</h2>
<h3>6. Use <a href="http://github.com/tobi/delayed_job">delayed_job</a></h3>
<p>Sometimes in the course of any web service, you run into some action that takes a little while to process. This is generally a pain and causes a whole host of problems, including frustrated users clicking refresh and spawning a dozen instances of your app all running the same long-running request and tying up valuable request slots. Long-running jobs, or jobs that absolutely must succeed are something of a royal pain in the patootie to handle gracefully. Fortunately, there&#8217;s DelayedJob, which is much like a double shot of Codine to ease that terrible pain.</p>
<p>The concept is pretty simple &#8211; rather than immediately executing a long-running task, you create a &#8220;job&#8221; for it, then use an asynchronous daemon to run your job for you.</p>
<p>For example, let&#8217;s say that your app wants to post to Twitter when you accomplish some task. This is all well and good if Twitter is up (ha!) and fast and isn&#8217;t experiencing any technical issues and you aren&#8217;t having any issues on your end and you don&#8217;t have any exceptions. In short, it&#8217;s fine when things don&#8217;t break, but we all know that things break and go wrong and generally end up sideways when you&#8217;re ever dealing with any kind of I/O, particularly of the remote web service kind. Rather than trying to post to Twitter in-process, we&#8217;ll create a job whose task is to post to Twitter.</p>
<p>Install the delayed_job gem, create the delayed_jobs table as indicated in its documentation, and write your first worker.</p>
<pre class="brush: ruby;">
module Jobs
	class PostToTwitter &lt; Struct.new(:username, :password, :tweet)
		def perform
			auth = Twitter::HTTPAuth.new(username, password)
			client = Twitter::Base.new(auth)
			client.update(tweet)
		end
	end
end
</pre>
<p>Now, in your controller code, or after_create in your model, or where ever, rather than posting to Twitter directly, just enqueue a job:</p>
<pre class="brush: ruby;">

Delayed::Job.enqueue Jobs::PostToTwitter.new(params[:username], params[:password], params[:tweet])
</pre>
<p>Finally, you&#8217;ll want to fire up a DelayedJob daemon. This is pretty easy to do under Rails.</p>
<p>Create a file called <code>script/worker.rb</code> and stick the following in it:</p>
<pre class="brush: ruby;">#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))

daemon_options = {
  :multiple =&gt;; false,
  :dir_mode =&gt; :normal,
  :dir =&gt; File.join(dir, 'tmp', 'pids'),
  :backtrace =&gt; true
}

Daemons.run_proc('job_runner', daemon_options) do
  if ARGV.include?('--')
    ARGV.slice! 0..ARGV.index('--')
  else
    ARGV.clear
  end

  Dir.chdir dir
  RAILS_ENV = ARGV.first || ENV['RAILS_ENV'] || 'development'
  require File.join('config', 'environment')

  Delayed::Worker.new.start
end
</pre>
<p>Now, all you have to do is call <code>script/worker start</code> and you&#8217;re up and running. Jobs will automatically be processed as they&#8217;re added to the queue. If they fail, the reason why will be logged and the job will be scheduled to be retried in the future. You can correct any mistakes and re-run the job and watch it happily succeed. If the mistake is on the remote end, then the worker will keep retrying it until it succeeds, and your user doesn&#8217;t have to sit there and wait while your app continually receives the API equivalent of the failwhale. Everyone is happy (eventually!)</p>
<p>Once you start using DelayedJob, you&#8217;ll find that there are lots of things you can do with it to smooth out your app&#8217;s user-response speed. Processing user avatars or large file uploads, recomputing expensive queries (like a social graph update), talking to remote web services, or even sending emails can all be moved away from the realtime and into the background with total ease.</p>
<h3>7. Use memcached</h3>
<p>This should probably be tip #1. Good caching can make or break a project, and memcached is a fantastic method for managing your caching. </p>
<blockquote><p>Memcached is an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering.</p></blockquote>
<p>By default, Rails writes page and fragment cache bits to disk. This is slow, is difficult to clean up after, adds a lot of wear-and-tear to your disk, and is generally undesirable. It&#8217;s used because it&#8217;s easy. Memcached is a far better solution &#8211; it is very much a &#8220;giant hash table in the sky&#8221;. Dump a value into memory, read it back out of memory later. It is extremely fast, and comes with some super dandy features like time-based expiration that disk caching just won&#8217;t get you.</p>
<p>Implementation in Rails is easy. First, install both the memcached daemon and the memcache client. Second, in your environment file, add something like so:</p>
<pre class="brush: ruby;">
require_library_or_gem 'memcache'
config.cache_store = :mem_cache_store, [&quot;localhost:11211&quot;]
</pre>
<p>By default, memcached runs on port 11211. Point Rails at it with the above directives and restart your app and that&#8217;s it. You&#8217;re running on memcached. No more ugly disk sweeping, and you get some really nice features. You can add multiple servers to the :mem_cache_store, too, which is several flavors of awesome. The memcached client will do automatic cluster management and balancing, so you can share the same cache between any number of servers, rather than each server having to have its own copy of that cache. Sweet!</p>
<pre class="brush: ruby;">
&lt;% cache(&quot;my_custom_fragment_name:#{@record_id}&quot;, :raw =&gt; true, :expires_in =&gt; 1.hour) do %&gt;
	&lt;%=render :partial =&gt; &quot;some_expensive_partial&quot;, :object =&gt; @record %&gt;
&lt;% end %&gt;
</pre>
<p>This is your standard fragment cache, but the <code>:raw</code> and <code>:expires_in</code> parameters are new.</p>
<p><code>:raw</code> tells the Ruby memcached client to not marshal the content before sticking it in memcached. Since you&#8217;re just storing a document fragment (that is, a string), marshaling a ruby string and then unmarshaling it when you want to read it back is both unnecessary and slow.</p>
<p><code>:expires_in</code> sets a maximum lifetime for this fragment. If we generate a fragment, memcached will timestamp it, and then if we try to read it back, say, 90 minutes later, memcached will recognize &#8220;oh hey, this fragment is expired! Sorry, I don&#8217;t have anything for you!&#8221;. Our view will regenerate and re-cache that fragment, and for the next 60 minutes, rather than trying to regenerate that fragment any time that view is called, it&#8217;ll just pull the cached copy from memcached.</p>
<p>If you need to ever flush your cache, it&#8217;s as easy as just restarting memcached. That&#8217;s it, really. In one fell swoop, you get faster caching (yay!), easier cache management (yay!), and a cache that can scale across multiple servers (double yay!)</p>
<h3>8. Use etags</h3>
<p>etags are a nifty little feature that are woefully under-used by most web developers. You can think of them as a fingerprint for a given page. Consider the following process:</p>
<ol>
<li>I request a page for the first time. The app generates the page and sends me both a copy of the page and a small hash finger print.</li>
<li>I request the page a second time, and send the fingerprint of my cached copy back to the server.</li>
<li>The server compares the fingerprint I sent with the fingerprint of its latest copy of the page. If they match, it just sends back a <code>304 Not Modified</code> header and stops rendering</li>
</ol>
<p>Sounds handy, right? Sure, and it&#8217;s really easy to implement in Rails. Let&#8217;s assume you have a <code>BlogController</code> which has a <code>show</code> method for showing a given blog post. You could use the following to implement etags:</p>
<pre class="brush: ruby;">
def show
	@post = BlogPost.find params[:id]
	@comments = @post.comments.paginate params[:page], 25
	return unless stale? :etag =&gt; [@post, @comments]
end
</pre>
<p>Wait, that&#8217;s it? Yes, actually! What&#8217;s happening there is Rails builds a fingerprint of the object(s) you the <code>:etag</code> parameter of the <code>stale?</code> method. If the objects don&#8217;t change, then the etag doesn&#8217;t change. This means that you would get different etags for the same blog post on a different page of comments (good!), or a different etag if a comment is added (good!) or a different etag if the post is edited (good!), but as long as those objects haven&#8217;t changed since the user&#8217;s last request of that action, the etag will be the same, and the action will stop running right there and tell the browser to just display its cached copy.</p>
<p>On heavily-trafficked pages that aren&#8217;t easily customized on a global scale (for example, if you have custom per-user bits on the page that mean that you can&#8217;t serve the same page to everyone), this is a really decent way to prevent excessive and wasteful application work. If you don&#8217;t use the <code>stale?</code> method, Rails always assumes that the page is stale, and thus needs to be regenerated. </p>
<p>On something of a tangent, can also use <code>stale? :last_modified => @post.updated_at</code> to determine if a page is fresh or stale. However, this does have the drawback of not being compatible with pagination, or sorted views, or anything of that nature. By using etags, you can ensure that each unique data set gets its own etag, and thus, doesn&#8217;t have cache collisions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/12/23/eight-tips-for-getting-the-most-out-of-your-rails-app/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>When you have to store user passwords&#8230;</title>
		<link>http://www.coffeepowered.net/2009/12/15/when-you-have-to-store-user-passwords/</link>
		<comments>http://www.coffeepowered.net/2009/12/15/when-you-have-to-store-user-passwords/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 10:14:42 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=203</guid>
		<description><![CDATA[Today we got word of yet-another-database-hack-with-plaintext-passwords. This time, it&#8217;s RockYou, purveyor of many of those Facebook and Myspace apps you use. Oops. Every time this comes up, everyone says &#8220;How naive! They should have been using salted hashed passwords!&#8221; This is true in any case where you don&#8217;t need to use the password again on [...]]]></description>
			<content:encoded><![CDATA[<p>Today we got word of yet-another-database-hack-with-plaintext-passwords.<a href="http://www.techcrunch.com/2009/12/14/rockyou-hack-security-myspace-facebook-passwords/"> This time, it&#8217;s RockYou</a>, purveyor of many of those Facebook and Myspace apps you use. Oops.</p>
<p>Every time this comes up, everyone says &#8220;How naive! They should have been using salted hashed passwords!&#8221; This is true in any case where you don&#8217;t need to use the password again on an external service. With OAuth solutions becoming more and more popular, the need to collect and store user passwords is fortunately becoming more and more rare. However, it does need to happen sometimes, so how do you take the proper precautions when you do need to?</p>
<p>The first step is to encrypt your data before it is persisted into your database. This is pretty easy to do, and there are a number of methods for it. Here&#8217;s an example of something I used in a Rails app to provide encryption services.</p>
<pre class="brush: ruby;">
require 'openssl'
require 'base64'
module Encryption
	class OpenSSL_Key
		PUBLIC_KEY_FILE = &quot;#{RAILS_ROOT}/config/public.pem&quot;
		PRIVATE_KEY_FILE = &quot;#{RAILS_ROOT}/config/private.pem&quot;

		def self.encrypt(data)
			@@public_key ||= OpenSSL::PKey::RSA.new(File.read(PUBLIC_KEY_FILE))
			encrypted_data = @@public_key.public_encrypt(data)
			Base64.encode64(encrypted_data)
		end

		def self.decrypt(data)
			@@private_key ||= OpenSSL::PKey::RSA.new(File.read(PRIVATE_KEY_FILE))
			decoded_data = Base64.decode64(data)
			@@private_key.private_decrypt(decoded_data)
		end
	end

	class OpenSSL_RSA
		IV64 = &quot;xxxxxxxxxxxxxxxxxxxxxxxxxx==\n&quot;
		KEY64 = &quot;xxxxxxxxxxxxxxxxxxxxxxxxxx=\n&quot;
		CIPHER = 'aes-256-cbc'

		def self.encrypt(data)
			@@iv ||= Base64.decode64(IV64)
			@@key ||= Base64.decode64(KEY64)

			cipher = OpenSSL::Cipher::Cipher.new(CIPHER)
			cipher.encrypt
			cipher.key = @@key
			cipher.iv = @@iv
			encrypted_data = cipher.update(data)
			encrypted_data &lt;&lt; cipher.final
			Base64.encode64(encrypted_data)
		end

		def self.decrypt(data)
			@@iv ||= Base64.decode64(IV64)
			@@key ||= Base64.decode64(KEY64)

			cipher = OpenSSL::Cipher::Cipher.new(CIPHER)
			cipher.decrypt
			cipher.key = @@key
			cipher.iv = @@iv
			decrypted_data = cipher.update(Base64.decode64(data))
			decrypted_data &lt;&lt; cipher.final
		end
	end
end
</pre>
<p>This provides two classes, <code>Encryption::OpenSSL_Key</code> and <code>Encryption::OpenSSL_RSA</code> which may be used to encrypt arbitrary strings. The OpenSSL_Key class uses a public/private keypair (in our example, read out of the Rails config directory), and the OpenSSL_RSA class uses an initialization vector and secret key. The latter is probably easier, since it means you don&#8217;t have to worry about keypairs, and since all the encrypt/decrypt is done locally, there isn&#8217;t any need for public public encryption.</p>
<p>Once you have that file in your project, using it is pretty simple.</p>
<pre class="brush: ruby;">
# Our databse is going to have a field called encrypted_password. We'll use attr_accessor for the password itself.

class MySecretModal &lt; ActiveRecord::Base
	before_save :encrypt_fields
	attr_accessor :password

	def password
		@decrypted_password ||= decrypt_field(:password)
	end

private

	def encrypt_fields
		write_attribute :encrypted_password, Encryption::OpenSSL_RSA.encrypt(@password)
	end

	def decrypt_field(field)
		Encryption::OpenSSL_RSA.decrypt read_attribute(&quot;encrypted_#{field}&quot;)
	end
end
</pre>
<p>The net result is that we can still get access to the raw password if we need to, but the content in the database will be RSA-encrypted against a secret key in our application. This is still vulnerable if the attacker gains access to the file containing your RSA IV/key, or if he gains access to your public/private keypair, but it is extremely resilient in the case that an attacker manages to simply dump your users table via SQL injection. You still need to practice good key management, and you absolutely should not use a technique this simplistic for storing financial data &#8211; there are a whole set of guidelines and procedures for that kind of information. However, for adding an extra layer of defense to save yourself and your customers from excess embarrassment in the case of a database breach, this is a quick, easy, and effective technique for hardening your data.</p>
<p>This is a rather raw implementation, and there are ways you could package it up so that you could transparently apply it to any number of models or fields, but the basic technique is solid. You could even use something like <a href="http://github.com/Mechaferret/sql_crypt">sql_crypt</a> to easily protect sensitive fields. The technology is there, and &#8220;We needed to be able to re-use the password!&#8221; isn&#8217;t an excuse anymore. Stop storing plaintext passwords &#8211; just like backups, it&#8217;s just extra work until you need it, and then you&#8217;ll be glad you put that extra work in.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/12/15/when-you-have-to-store-user-passwords/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Fine tuning your garbage collector</title>
		<link>http://www.coffeepowered.net/2009/06/13/fine-tuning-your-garbage-collector/</link>
		<comments>http://www.coffeepowered.net/2009/06/13/fine-tuning-your-garbage-collector/#comments</comments>
		<pubDate>Sun, 14 Jun 2009 02:52:13 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=173</guid>
		<description><![CDATA[If you&#8217;re familiar with Ruby at all, you know that it can be a little wacky when it comes to memory usage. Most of us have observed a Mongrel/Passenger instance that starts out small and then grows by leaps and bounds, eventually settling on some uncomfortably high number. We&#8217;re going to fix that with Ruby [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re familiar with Ruby at all, you know that it can be a little wacky when it comes to memory usage. Most of us have observed a Mongrel/Passenger instance that starts out small and then grows by leaps and bounds, eventually settling on some uncomfortably high number. We&#8217;re going to fix that with <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a> and <a href="http://github.com/cheald/scrap/tree/master">Scrap</a>.<br />
<span id="more-173"></span><br />
The Ruby garbage collector&#8217;s behavior is controlled by a number of constants. In the MRI, these are compiled into Ruby itself, and don&#8217;t change. However, if you&#8217;re using REE you can override them with environment variables on startup. It&#8217;s terribly handy.</p>
<h3>First, the boring documentation</h3>
<p>All the juicy information is available <a href="http://www.rubyenterpriseedition.com/documentation.html#_garbage_collector_performance_tuning">in the documentation</a>, but I&#8217;m going to just go over the key points real quick.</p>
<p><code>RUBY_HEAP_MIN_SLOTS</code>: This is the number of &#8220;heap slots&#8221; that each Ruby instance starts up with. One heap slot can hold one Ruby object. By default, this is 10,000. By controlling this value, we can get our apps to stabilize very quickly. More on this later.</p>
<p><code>RUBY_HEAP_SLOTS_INCREMENT</code>: Once Ruby has allocated <code>RUBY_HEAP_MIN_SLOTS</code> objects on its first heap, it will have to allocate a second heap to make room for more. This variable controls the size of this second heap, and sets the baseline for future heaps, as well.</p>
<p><code>RUBY_HEAP_SLOTS_GROWTH_FACTOR</code>: For heaps #3 and onward, Ruby uses <code>RUBY_HEAP_SLOTS_INCREMENT</code> and this value to determine the size to allocate for the new heap. By default, this is 1.8, meaning that your third heap will end up with 10,000 * 1.8 = 18,000 slots in it.</p>
<p><code>RUBY_HEAP_FREE_MIN</code>: After each garbage collection run, if the number of free slots is less than <code>RUBY_HEAP_FREE_MIN</code>, a new heap will be allocated. The default is 4096.</p>
<p>So, let&#8217;s look at this practically. Presume that we have a Rails process that is going to require 50,000 Ruby objects before it&#8217;s fully initialized. The allocation process, when at defaults, will look something like this:</p>
<p>Allocate 10,000 slots (10,000 total available)<br />
Allocate 10,000 slots (20,000 total available)<br />
Allocate 18,000 slots (38,000 total available)<br />
Allocate 68,400 slots (106,400 total available)</p>
<p>So, we end up with about 53% more slots than we actually needed, and it took us four heap allocations to even boot the process. Surely we can do better.</p>
<h3>Enter Scrap.</h3>
<p><a href="http://github.com/cheald/scrap/tree/master">Scrap</a> is a little <a href="http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal">Metal</a> handler I wrote for tracking memory usage and garbage statistics over an instance&#8217;s lifetime. Installing it is trivial &#8211; just drop it into your vendor directory, restart your app, and navigate to <code>http://yoururl.com/stats/scrap</code>.</p>
<p>With this in hand, we can peek our memory usage and see what we can see.</p>
<p>There are some stats at the top, but for our purposes, we&#8217;re interested in the per-request garbage statistics. The newest request is near the top of the file, and the oldest request is at the bottom of the file. The last 50 requests are tracked. Each request looks something like this:</p>
<pre><code>
[71.92 MB] GET /apps/176568-WordPress

Number of objects    : 817571 (658305 AST nodes, 80.52%)
Heap slot size       : 20
GC cycles so far     : 503
Number of heaps      : 7
Total size of objects: 15968.18 KB
Total size of heaps  : 18036.81 KB (2068.63 KB = 11.47% unused)
Leading free slots   : 27104 (529.38 KB = 2.93%)
Trailing free slots  : 1 (0.02 KB = 0.00%)
Number of contiguous groups of 16 slots: 2829 (4.90%)
Number of terminal objects: 4307 (0.47%)
</code></pre>
<p>Key points here for the time being are <code>Number of objects</code> and <code>Number of heaps</code>. When we look at the number of objects &#8211; in this case, 817,000, it&#8217;s obvious that we&#8217;re going to have to allocate a number of heaps to handle all those objects. Rails&#8217; boot-up cost is fairly significant, and the default Ruby settings just really don&#8217;t cut it here. As you can see, we&#8217;ve allocated 7 heaps, and we&#8217;re using 15.9 of 18.0 MB allocated to the heap. Once a heap is allocated, it&#8217;s never de-allocated, so we&#8217;re perma-stuck at 18 MB of heap usage. Note that this isn&#8217;t the size of all the data in the program &#8211; just the space allocated for objects. A string that contains 100MB of data will only consume 20 bytes (that&#8217;s the &#8220;heap slot size &#8211; the amount of memory each object on the heap consumes&#8221;) on the heap. </p>
<p>However, what if we could just allocate the whole startup cost in the initial heap, and save ourselves the problems of having to reallocate so often?</p>
<p>We note that we have 891k slots allocated, so we can guesstimate at a number to set our initial allocation to. In my production app, I set mine to 1,250,000 &#8211; I was observing peaks around the 1,100,000 mark, and just increased it by 10% and rounded up.</p>
<p>So, my first custom environment variable is </p>
<p><code>RUBY_HEAP_MIN_SLOTS=1250000</code></p>
<p>And it results in something like this on the app&#8217;s first boot:</p>
<p>[137.99 MB] GET /movies/7505-Star-Wars-Episode-V-The-Empire-Strikes-Back</p>
<pre><code>Number of objects    : 933037 (664785 AST nodes, 71.25%)
Heap slot size       : 20
GC cycles so far     : 12
Number of heaps      : 1
Total size of objects: 18223.38 KB
Total size of heaps  : 24414.08 KB (6190.70 KB = 25.36% unused)
Leading free slots   : 316963 (6190.68 KB = 25.36%)
Trailing free slots  : 0 (0.00 KB = 0.00%)
Number of contiguous groups of 16 slots: 19810 (25.36%)
Number of terminal objects: 25941 (2.08%)</code></pre>
<p>Yowza, a full 25% of my heap is unused after boot. But&#8230;well, that&#8217;s okay. We&#8217;ve only allocated 1 heap, and later on, my object allocation grows to around 1,100,000. This is still 15k under the heap size, and I&#8217;ve set <code>RUBY_HEAP_FREE_MIN=12500</code> (1% of the initial size), so if I have less than 12,500 heap objects free after a GC cycle, a new heap will be allocated. Stabilizing there means that I end up with 1 heap for the lifetime of my app, and I end up sitting just under the threshold that&#8217;d cause a new heap to be born. If I have a leak, or a super heavy action or something, though, that might kick me over my limit and require a new heap. So, we come to&#8230;</p>
<p><code>RUBY_HEAP_SLOTS_INCREMENT=100000</code></p>
<p>This value says &#8220;Hey, if you have to allocate a second heap, start with this many slots&#8221;. If we go over our limit of 1.25 million slots, we&#8217;ll allocate a second heap that&#8217;s about 8% the size of the original. That seems awfully small, but consider that we&#8217;re hoping to never get to that heap.</p>
<p>Should we end up using that entire second heap, then we have to worry about our third setting, <code>RUBY_HEAP_SLOTS_GROWTH_FACTOR=1</code>. This says &#8220;Each new heap should be 1.0 as large as the previous heap.&#8221; In this case, it means I&#8217;ll keep allocating 100k-slot heaps until the cows come home. In an untuned environment, this could be bad &#8211; we would either end up having to do a <em>ton</em> of allocations to get to our target, or we would overallocate very badly. However, because we know our app&#8217;s memory requirements, and know about where we want it to end up, a relatively small, linear growth factor is just what the doctor ordered here.</p>
<h3>Okay, now what?</h3>
<p>So, we have a collection of settings with which to run our app. Great! Now, how do we use it?</p>
<p>Fortunately, it&#8217;s easy.</p>
<pre><code>
pushd `which ruby | xargs dirname`
sudo vim ruby-with-env
</code></pre>
<p>We&#8217;re going to create a little bash script with the following:</p>
<pre class="brush: ruby;">
#!/bin/bash
export RUBY_HEAP_MIN_SLOTS=1250000
export RUBY_HEAP_SLOTS_INCREMENT=100000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_GC_MALLOC_LIMIT=30000000
export RUBY_HEAP_FREE_MIN=12500
exec &quot;/opt/ree/bin/ruby&quot; &quot;$@&quot;
</pre>
<p>Note that last line &#8211; the path will have to match the path to your Ruby executable, which fortunately, should be in the directory that you&#8217;re in.</p>
<p>Save it, don&#8217;t forget to <code>chmod a+x ruby-with-env</code>, and then edit your Apache or nginx configuration.</p>
<p>Under nginx, you&#8217;ll have a line like this:</p>
<p><code>passenger_ruby /opt/ruby-enterprise-1.8.6-20090610/bin/ruby;</code></p>
<p>Just change it to use your new wrapper script, like so:</p>
<p><code>passenger_ruby /opt/ruby-enterprise-1.8.6-20090610/bin/ruby-with-env;</code></p>
<p>The process is similarly easy for Apache &#8211; the line you need is something like:</p>
<p><code>PassengerRuby /opt/ruby-enterprise-1.8.6-20090610/bin/ruby</code></p>
<p>It might be in either your <code>httpd.conf</code> or <code>conf.d/passenger.conf</code>.</p>
<p>Once you&#8217;re all edited up, restart your webserver, and congratulations, you&#8217;ve got a fine-tuned garbage collector humming along with your app.</p>
<h3>Taking out the garbage</h3>
<p>&#8220;But Chris!&#8221;, you say, &#8220;There&#8217;s a variable in there that you didn&#8217;t talk about! What gives?&#8221; You are indeed correct, astute reader. We&#8217;ve thus far avoided the <code>RUBY_GC_MALLOC_LIMIT</code> variable. This is a handle little setting that lets you tell Ruby how often to clean up after itself. Ruby is written in C, and C uses <code>malloc</code> to allocate memory. Ruby just keeps a little counter each time it allocates an object with malloc, and it runs its garbage collector after so many malloc calls have been made. I haven&#8217;t found a great way to tune this one yet, except via experimentation, but here&#8217;s what to know about it:</p>
<ol>
<li>The lower this value is, the more often your garbage collector runs. Garbage collection is slow. Garbage collection is painfully slow. If a user is waiting on garbage collection, they are going to become impatient. You want as few users waiting on garbage collection as possible.</li>
<li>The higher this value is, the more memory Ruby will allocate before it tries to clean up after itself. If this value is too high, you&#8217;ll have dead objects hanging around eating up heap space, and possibly causing Ruby to crap itself and allocate a new heap. This is bad.</li>
<li>To tune this value, you want to find the happy medium, wherein you stabilize under your initial heap allocation value, but with as few garbage collection passes as possible. Read up on <a href="http://blog.evanweaver.com/articles/2009/04/09/ruby-gc-tuning/">Evan Weaver&#8217;s blog</a> for some more in-depth analysis of what garbage collection frequency tuning can do to your app&#8217;s performance.
<li>If you have excess memory and want a faster app, err on the side of this being too high. If you are on a tight memory budget, and would prefer slower actions in exchange for not blowing your heap and allocating a whole new one, err on the side of this being too low.</li>
<li>Recommended values for this are all over the board. Evan recommends a setting of 50 million. I&#8217;m using a setting of 30 million. The Ruby default is 8 million. You&#8217;ll have to play around and find what works best for you. Just pay attention to how many requests there are in between that &#8220;GC cycles so far&#8221; number incrementing in Scrap, and you&#8217;ll be able to measure approximately how often you&#8217;re entering a GC cycle.
</ol>
<p>Good luck with it, and have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/06/13/fine-tuning-your-garbage-collector/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Announcing Scrap</title>
		<link>http://www.coffeepowered.net/2009/03/24/announcing-scrap/</link>
		<comments>http://www.coffeepowered.net/2009/03/24/announcing-scrap/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 10:02:09 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[metal]]></category>
		<category><![CDATA[objectspace]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=159</guid>
		<description><![CDATA[I do a lot of memory and garbage analysis on my Rails apps, and in upgrading to Rails 2.3, I discovered a practical use for the new Rails Metal middleware. Dumping memory stats to my log was just sorta unreadable in a practical scenario, and was more or less entirely unusable in production. Fortunately, Metal [...]]]></description>
			<content:encoded><![CDATA[<p>I do a lot of memory and garbage analysis on my Rails apps, and in upgrading to Rails 2.3, I discovered a practical use for the new <a href="http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal">Rails Metal</a> middleware. Dumping memory stats to my log was just sorta unreadable in a practical scenario, and was more or less entirely unusable in production. Fortunately, Metal provides a really easy way to output readable information to the browser without invoking the full Rails stack. (It&#8217;s also an excuse to write a Metal endpoint because it&#8217;s new and shiny, but that&#8217;s beside the point.)</p>
<p>It&#8217;s up at <a href="http://github.com/cheald/scrap/tree/master">github</a> &#8211; installation is dead easy (assuming you&#8217;re on Rails 2.3+, of course) &#8211; just install the plugin, restart your app, and hit <code>&lt;your url&gt;/stats/scrap</code> in your browser. Bam, instant juicy memory goodness about your app at your fingertips. If you&#8217;d like an example of the output, good news! Check it out at <a href="http://tachyonsix.com/scrap.htm">http://tachyonsix.com/scrap.htm</a>.</p>
<p>You can use it to troubleshoot heap leaks &#8211; just run a few requests, hit your Scrap URL, and see what your deltas look like. Seeing a huge growth in a certain type of object? Chances are pretty good that you have a heap leak, and can start tracking it down.</p>
<p>The request history can help you locate certain actions that might be causing spikes in memory usage. It&#8217;ll show the last N requests, along with memory and heap statistics before each request. If there&#8217;s a consistent memory usage leap after a certain action, chances are that it&#8217;s doing something naughty.</p>
<p>Want to get a bigger picture on what objects are hanging around? You can use the <code>config/scrap.yml</code> file to get Scrap to spit out more detailed reports on instances of a given class. There&#8217;s full documentation on it in the README.</p>
<p>Anyhow, give it a shot, let me know what you think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/03/24/announcing-scrap/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Monitoring Rails: Getting instant monitoring alerts</title>
		<link>http://www.coffeepowered.net/2009/03/13/monitoring-rails-getting-instant-monitoring-alerts/</link>
		<comments>http://www.coffeepowered.net/2009/03/13/monitoring-rails-getting-instant-monitoring-alerts/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 08:58:31 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[jabberish]]></category>
		<category><![CDATA[monitoring]]></category>
		<category><![CDATA[uptime]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=145</guid>
		<description><![CDATA[Monitoring is big. Having an automated daemon watch your stuff and make sure it&#8217;s running properly can let you sleep at night, knowing that if something blows up, there&#8217;s an ever-watchful guardian ready to wake you up so you can fix it. There are a number of monitoring solutions that are popular these days, such [...]]]></description>
			<content:encoded><![CDATA[<p>Monitoring is big. Having an automated daemon watch your stuff and make sure it&#8217;s running properly can let you sleep at night, knowing that if something blows up, there&#8217;s an ever-watchful guardian ready to wake you up so you can fix it.</p>
<p>There are a number of monitoring solutions that are popular these days, such as <a href="http://mmonit.com/monit/">monit</a>, <a href="http://god.rubyforge.org/">god</a>, and <a href="http://www.nagios.org/">Nagios</a>. They&#8217;re all fantastic, but sometimes you just want something simple and to-the-point, right?</p>
<p><span id="more-145"></span></p>
<p>With <a href="http://github.com/cheald/jabberish/tree/master/">jabberish</a> in your project, this becomes a no-brainer. I&#8217;m already using Jabberish in my project, so I whipped up a little script that checks system load, available memory, and any changes in swap usage and shoots me an IM under certain conditions. My monitoring still handles automated maintenance in the case of a runaway process or whatnot, but this keeps me instantly informed of any problems that my system might be running in to.</p>
<pre class="brush: ruby;">
require 'rubygems'
require 'drb'
require 'daemons'

MAX_MEMORY = 95
MAX_LOAD = 4.0
DELIVER_TO = &quot;cheald@gmail.com&quot;
JABBERISH_SERVER = &quot;druby://localhost:35505&quot;

$warned = {}
$hostname = `hostname`.strip

def im
	$im_service ||= DRbObject.new(nil, JABBERISH_SERVER)
end

def deliver(msg)
	im.deliver DELIVER_TO, &quot;[#{$hostname}] #{msg}&quot;
end

def check_stats
	meminfo = open(&quot;/proc/meminfo&quot;).read

	mtotal = meminfo.match(/MemTotal:\s+(\d+)/)[1].to_i
	mfree = meminfo.match(/MemFree:\s+(\d+)/)[1].to_i
	mused = mtotal - mfree

	stotal = meminfo.match(/SwapTotal:\s+(\d+)/)[1].to_i
	sfree = meminfo.match(/SwapFree:\s+(\d+)/)[1].to_i
	sused = stotal - sfree

	begin
		if $warned[:swap] and sused &gt; $warned[:swap] then
			deliver &quot;WARNING: Swap has increased from #{$warned[:swap]} to #{sused}&quot;
		end
		$warned[:swap] = sused

		pct = mused / mtotal.to_f * 100.0
		if pct &gt; MAX_MEMORY then
			unless $warned[:memory]
				deliver sprintf(&quot;ALERT: Memory free: %2.2fmb (%2.2f%% used)&quot;, mfree / 1024.0, pct)
				$warned[:memory] = true
			end
		else
			$warned[:memory] = false
		end

		load = open(&quot;/proc/loadavg&quot;).read.split(&quot; &quot;).first
		if load &gt; MAX_LOAD then
			unless $warned[:load]
				deliver sprintf(&quot;WARNING: Load average is %s&quot;, load)
				$warned[:load] = true
			end
		else
			$warned[:load] = false
		end
	rescue
		puts &quot;Error: #{$!}&quot;
	end
end

Daemons.daemonize(:backtrace =&gt; true)

loop {
	check_stats
	sleep(10)
}
</pre>
<p>Not too bad, huh? This is written for a CentOS installation, so you may need to change things like the meminfo regexes depending on your system. It could probably use a YAML config file to be truly correct &#8211; configuration options in constants works, but is a little ugly.</p>
<p>Now I get alerts like these via instant message:</p>
<pre class="brush: ruby;">
[iceman.tagteam] WARNING: Load average is 4.44
[iceman.tagteam] ALERT: Memory free: 99.82mb (93.38% used)
[polaris.tagteam] ALERT: Memory free: 72.20mb (95.14% used)
</pre>
<p>This lets me respond to changing system conditions extremely rapidly, and serves as a high-level alert log when when I&#8217;m not at the keyboard &#8211; when I get back, I check my messages from blippr, and can see when and how often certain marginal conditions are being met.</p>
<p>Hope it&#8217;s useful!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/03/13/monitoring-rails-getting-instant-monitoring-alerts/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Syntactic sugar will occassionally kick your puppies.</title>
		<link>http://www.coffeepowered.net/2009/03/02/syntactic-sugar-will-occassionally-kick-your-puppies/</link>
		<comments>http://www.coffeepowered.net/2009/03/02/syntactic-sugar-will-occassionally-kick-your-puppies/#comments</comments>
		<pubDate>Mon, 02 Mar 2009 20:55:03 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=133</guid>
		<description><![CDATA[Ruby&#8217;s awesome. It has sweet, concise syntax that makes for clean, readable code. One of these constructs is the trailing condition. In most languages where you might have to write something like: if foo then do_stuff end Ruby will let you clean that up with: do_stuff if foo This works just nearly all the time, [...]]]></description>
			<content:encoded><![CDATA[<p>Ruby&#8217;s awesome. It has sweet, concise syntax that makes for clean, readable code. One of these constructs is the trailing condition. In most languages where you might have to write something like:</p>
<pre class="brush: ruby;">
if foo then
	do_stuff
end
</pre>
<p>Ruby will let you clean that up with:</p>
<pre class="brush: ruby;">do_stuff if foo</pre>
<p>This works just nearly all the time, but I ran into an odd problem today, where the trailing conditions were producing behavior I didn&#8217;t want.</p>
<pre class="brush: ruby;">
&gt;&gt; foobar
NameError: undefined local variable or method `foobar' for #&lt;Object:0x92bc998&gt;
        from (irb#1):2
&gt;&gt; foobar = true unless defined?(foobar)
=&gt; nil
&gt;&gt; foobar
=&gt; nil
&gt;&gt; unless defined?(foobar); foobar = true; end
=&gt; true
&gt;&gt; foobar
=&gt; true
</pre>
<p>Wait, what? Using the trailing conditional changes the order in which Ruby parses the statement, resulting in something like the following operations:</p>
<ol>
<li>Define <code>foobar</code> because it&#8217;s referenced, set it to <code>nil</code></li>
<li>Parse the <code>unless</code> conditional</li>
<li>If the condition is true, set <code>foobar</code> to <code>true</code></li>
</ol>
<p>The kicker here is that because <code>foobar</code>&#8216;s assignment is the first thing parsed, it&#8217;s always initialized before you ever get to the <code>defined?</code> statement. So instead, we run the second piece of code:</p>
<pre class="brush: ruby;">
unless defined?(foobar); foobar = true; end
</pre>
<p>This runs something like the following:</p>
<ol>
<li>Parse the <code>unless</code> condition.</li>
<li>Define <code>foobar </code>because it&#8217;s referenced, set it to <code>nil</code></li>
<li>If the condition is true, set <code>foobar </code>to <code>true</code></li>
</ol>
<p>Obviously this is the desired behavior. Several lessons here:</p>
<ul>
<li>Ruby initializes variables <em>when they are parsed</em>, not when the code path that contains them is run (in fact, it&#8217;ll even initialize variables that are in unreachable code paths!)</li>
<li><code>if condition then do_stuff end</code> is not always the same as <code>do_stuff if condition</code></li>
</ul>
<p>It&#8217;s a bit of an edge case, but it&#8217;s an edge case that had me baffled. Hopefully this post saves you some frustration.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/03/02/syntactic-sugar-will-occassionally-kick-your-puppies/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Mass inserting data in Rails without killing your performance</title>
		<link>http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/</link>
		<comments>http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/#comments</comments>
		<pubDate>Sat, 24 Jan 2009 03:55:59 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=82</guid>
		<description><![CDATA[Mass inserting is one of those operations that isn&#8217;t really well-supported by ActiveRecord, but which has to be done nonethless. You might say, &#8220;Well hey, I&#8217;ll just run a loop and create a bunch of AR objects, no sweat&#8221;. That&#8217;ll work, but if speed is a factor, it might not be your best option. ActiveRecord [...]]]></description>
			<content:encoded><![CDATA[<p>Mass inserting is one of those operations that isn&#8217;t really well-supported by ActiveRecord, but which has to be done nonethless. You might say, &#8220;Well hey, I&#8217;ll just run a loop and create a bunch of AR objects, no sweat&#8221;.</p>
<p>That&#8217;ll work, but if speed is a factor, it might not be your best option.</p>
<p>ActiveRecord makes interface to the DB very easy, but it doesn&#8217;t necessarily make it fast. Instantiating an ActiveRecord object is costly, and if you do a lot of &#8216;em, that&#8217;s going to cause you to bump up against the garbage collector, which will significantly hinder performance. There are several options, though, depending on how much speed you need.</p>
<p>There are benchmarks at the bottom of the post, so if you&#8217;re just interested in those, scroll down.<br />
<span id="more-82"></span></p>
<h2>Option 1: Use transactions</h2>
<p>This is definitely the easiest method, and while you&#8217;ll realize gains from it, you aren&#8217;t going to be breaking any speed records using only this method. However, it&#8217;s well worth it if you are doing mass inserts via ActiveRecord.</p>
<p>Instead of</p>
<pre class="brush: ruby;">
1000.times { Model.create(options) }
</pre>
<p>You want:</p>
<pre class="brush: ruby;">
ActiveRecord::Base.transaction do
  1000.times { Model.create(options) }
end
</pre>
<p>The net effect is that the database performs all of your inserts in a single transaction, rather than starting and committing a new transaction for every request.</p>
<h2>Options 2: Get down and dirty with the raw SQL</h2>
<p>If you know that your data is valid and can afford to skip validations, you can save a <b>lot</b> of time by just jumping directly to raw SQL.</p>
<p>Imagine, for example, that you&#8217;re running the following:</p>
<pre class="brush: ruby;">
1000.times {|i| Foo.create(:counter =&gt; i) }
</pre>
<p>That&#8217;s going to create 1000 ActiveRecord objects, run validations, generate the insert SQL, and dump it into the database. You can realize large performance gains by just jumping directly to the generated SQL.</p>
<pre class="brush: ruby;">
1000.times do |i|
  Foo.connection.execute &quot;INSERT INTO foos (counter) values (#{i})&quot;
end
</pre>
<p>You should use <code>sanitize_sql</code> and such as necessary to sanitize input values if they are not already sanitized, but with this technique you can realize extremely large performance gains. Of course, wrapping all those inserts in a single transaction, as in Option 1 gets you even more performance.</p>
<pre class="brush: ruby;">
Foo.transaction do
  1000.times do |i|
    Foo.connection.execute &quot;INSERT INTO foos (counter) values (#{i})&quot;
  end
end
</pre>
<h2>Option 3: A single mass insert</h2>
<p>Many databases support mass inserts of data in a single insert statement. They are able to significantly optimize this operation under the hood, and if you&#8217;re comfortable using it, will be your fastest option by far.</p>
<pre class="brush: ruby;">
inserts = []
TIMES.times do
  inserts.push &quot;(3.0, '2009-01-23 20:21:13', 2, 1)&quot;
end
sql = &quot;INSERT INTO user_node_scores (`score`, `updated_at`, `node_id`, `user_id`) VALUES #{inserts.join(&quot;, &quot;)}&quot;
</pre>
<p>No transaction block is necessary here, since it&#8217;s just a single statement, and the DB will wrap it in a transaction. We build an array of value sets to include, then just join them into the <code>INSERT</code> statement. We don&#8217;t use string concatenation, since it will result in significantly more string garbage generated, which could potentially get us into the GC, which we&#8217;re trying to avoid (and hey, memory savings are always good).</p>
<h2>Option 4: ActiveRecord::Extensions</h2>
<p>njero in <code>#rubyonrails</code> pointed me at <a href="http://www.continuousthinking.com/tags/arext/rdoc/index.html">this nifty little gem</a> and I decided to include it. It seems to try to intelligently do mass inserts of data. I wasn&#8217;t able to get it to emulate the single mass insert for a MySQL database, but it does provide a significant speed increase without much additional work, and can preserve your validations and such.</p>
<p>There&#8217;s the obvious added benefit that you stay in pure Ruby, and don&#8217;t have to get into the raw SQL.</p>
<pre class="brush: ruby;">
columns = [:score, :node_id, :user_id]
values = []
TIMES.times do
	values.push [3, 2, 1]
end

UserNodeScore.import columns, values
</pre>
<h2>Benchmarks</h2>
<p>I used a simple script to test each of the methods described here.</p>
<pre class="brush: ruby;">
require &quot;ar-extensions&quot;

CONN = ActiveRecord::Base.connection
TIMES = 10000

def do_inserts
	TIMES.times { UserNodeScore.create(:user_id =&gt; 1, :node_id =&gt; 2, :score =&gt; 3) }
end

def raw_sql
	TIMES.times { CONN.execute &quot;INSERT INTO `user_node_scores` (`score`, `updated_at`, `node_id`, `user_id`) VALUES(3.0, '2009-01-23 20:21:13', 2, 1)&quot; }
end

def mass_insert
	inserts = []
	TIMES.times do
		inserts.push &quot;(3.0, '2009-01-23 20:21:13', 2, 1)&quot;
	end
	sql = &quot;INSERT INTO user_node_scores (`score`, `updated_at`, `node_id`, `user_id`) VALUES #{inserts.join(&quot;, &quot;)}&quot;
	CONN.execute sql
end

def activerecord_extensions_mass_insert(validate = true)
	columns = [:score, :node_id, :user_id]
	values = []
	TIMES.times do
		values.push [3, 2, 1]
	end

	UserNodeScore.import columns, values, {:validate =&gt; validate}
end

puts &quot;Testing various insert methods for #{TIMES} inserts\n&quot;
puts &quot;ActiveRecord without transaction:&quot;
puts base = Benchmark.measure { do_inserts }

puts &quot;ActiveRecord with transaction:&quot;
puts bench = Benchmark.measure { ActiveRecord::Base.transaction { do_inserts } }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;Raw SQL without transaction:&quot;
puts bench = Benchmark.measure { raw_sql }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;Raw SQL with transaction:&quot;
puts bench = Benchmark.measure { ActiveRecord::Base.transaction { raw_sql } }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;Single mass insert:&quot;
puts bench = Benchmark.measure { mass_insert }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;ActiveRecord::Extensions mass insert:&quot;
puts bench = Benchmark.measure { activerecord_extensions_mass_insert }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;ActiveRecord::Extensions mass insert without validations:&quot;
puts bench = Benchmark.measure { activerecord_extensions_mass_insert(true)  }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)
</pre>
<p>And the results:</p>
<pre class="brush: ruby;">
Testing various insert methods for 10000 inserts
ActiveRecord without transaction:
 14.930000   0.640000  15.570000 ( 18.898352)
ActiveRecord with transaction:
 13.420000   0.310000  13.730000 ( 14.619136)
  1.29x faster than base
Raw SQL without transaction:
  0.920000   0.170000   1.090000 (  3.731032)
  5.07x faster than base
Raw SQL with transaction:
  0.870000   0.150000   1.020000 (  1.648834)
  11.46x faster than base
Single mass insert:
  0.000000   0.000000   0.000000 (  0.268634)
  70.35x faster than base
ActiveRecord::Extensions mass insert:
  6.580000   0.280000   6.860000 (  9.409169)
  2.01x faster than base
ActiveRecord::Extensions mass insert without validations:
  6.550000   0.240000   6.790000 (  9.446273)
  2.00x faster than base
</pre>
<p>The results are fairly self-explainatory, but of particular note is the specific single INSERT statement. At 70x faster than the non-transactional ActiveRecord insert, if you need speed, it&#8217;s hard to beat.</p>
<h2>Conclusions</h2>
<p>ActiveRecord is great, but sometimes it&#8217;ll hold you back. Finding the balance between ease of use (full ActiveRecord) and performance (bare metal mass inserts) can have a profound effect on the performance of your app.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using memcached
Page Caching using memcached
Database Caching 12/18 queries in 0.011 seconds using memcached

Served from: www.coffeepowered.net @ 2010-09-09 10:41:07 -->