<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>OnMyList Blog: memcached and cache_fu</title>
    <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>List your pants off!</description>
    <item>
      <title>memcached and cache_fu</title>
      <description>&lt;p&gt;After going live for about a week it became obvious that we should implement caching to help performance. I experimented with Rails&amp;#8217; page caching, but in Rails 1.2 the &lt;i&gt;expire_cache&lt;/i&gt; helper does not deal with custom routes very well. Also, our pages have view counts, ratings, etc, that change way too often for us to be able to cache the entire page.&lt;/p&gt;


	&lt;p&gt;The next thing I looked at was caching the MySQL queries, this seemed easier than implementing fragment caching, coz I found a &lt;a href="http://nubyonrails.com/articles/2006/08/17/memcached-basics-for-rails"&gt;CachedModel tutorial&lt;/a&gt; and it looked very good. Took me about an hour to get everything with CachedModel working, I then looked at the verbose output of memcached and my development.log, it didn&amp;#8217;t seem to be caching very much. After some more googling it turned out that CachedModel only caches find() queries, but we use custom finders in our models almost exclusively. To get it to cache more I had to manually cache and evict objects, which was kindda not fun.&lt;/p&gt;


	&lt;p&gt;So back to more googling, and I found a RailConf 2007 presentation  by &lt;a href="http://errtheblog.com"&gt;Chris Wanstrath&lt;/a&gt; on &lt;i&gt;cache_fu&lt;/i&gt;, it was appropriately titled &lt;a href="http://errtheblog.com/post/4872"&gt;&lt;em&gt;Kickin&amp;#8217; Ass with cache_fu&lt;/em&gt;&lt;/a&gt;. It seemed cool, and he talked about creating wrappers for custom finders, which was exactly what I needed. So I spent like an hour on it and moved from &lt;em&gt;CachedModel&lt;/em&gt; to &lt;i&gt;cache_fu&lt;/i&gt;.&lt;/p&gt;


	&lt;p&gt;I was all excited that it was so easy, almost too easy right? Yeah, I restarted my development server in &lt;a href="http://locomotive.raaum.org/"&gt;&lt;em&gt;Locomotive&lt;/em&gt;&lt;/a&gt;, loaded the main page, and was greeted with a &lt;i&gt;&amp;#8220;NoMethodError: protected method&amp;#8221;&lt;/i&gt; error. It was pretty weird, I spent quite a while trying to figure it out by going through the &lt;i&gt;cache_fu&lt;/i&gt; code, still couldn&amp;#8217;t figure out it. I emailed Chris, who was extremely helpful and replied to my mails in lightning fast speed (&lt;em&gt;thanks Chris!&lt;/em&gt;), he had never seen an error like that before either. After a while I went ahead and checked out cache_fu on our production server and ran the test suites that comes with it, it worked! Chris suspected that the problem had to do with Locomotive, I went ahead and installed a few gems to my global environment and ran the tests outside of the Locomotive sandbox, it worked! So after comparing the installed gem lists between Locomotive and MacPorts&amp;#8217; Ruby installation, I narrowed it down to the &lt;strong&gt;&lt;em&gt;Ruby-MemCache&lt;/em&gt;&lt;/strong&gt; gem. Uninstalled that, everything worked! So I thought I&amp;#8217;d blog about this in case someone run into the same problem in the future. I have no idea when I installed that gem, I guess the name looked good so I installed it.&lt;/p&gt;


	&lt;p&gt;cache_fu is pretty neat, I created finders that check if there are cached version of the data and I&amp;#8217;m using these new finders in our controllers, for example, here&amp;#8217;s how the custom finder that locates recently updated lists looks like (I&amp;#8217;ve removed some irrelevant code):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;List.recently_updated&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
  &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;find_conditions&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; 
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; AND (lists.is_private=0 OR lists.is_private IS NULL)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="ident"&gt;lists&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;List&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
    &lt;span class="symbol"&gt;:order&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;updated_at DESC&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:limit&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
    &lt;span class="symbol"&gt;:offset&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;  

  &lt;span class="ident"&gt;lists&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;List&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;cached_perform_roster_sort&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;lists&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
    &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;lists&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The cached version of it looks like this:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;List.cached_recently_updated&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
  &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;get_cache&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;recently_updated:&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt;
    &lt;span class="ident"&gt;conditions&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; 
    &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;

    &lt;span class="ident"&gt;recently_updated&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
      &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;pretty clean and simple! :) We&amp;#8217;re testing the version of our site that uses memcached right now, if all goes well we will deploy it to the live site and hopefully you will enjoy a nice speedup.&lt;/p&gt;


	&lt;p&gt;Now we just have to tune the caching a bit, probably will add fragment caching to various places. Next big thing for me is to scale, right now we&amp;#8217;re considering &lt;a href="http://aws.amazon.com/ec2"&gt;&lt;span class="caps"&gt;EC2&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://joyent.com/accelerator"&gt;Joyent&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 15 Jun 2007 00:12:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:af20293b-0bf3-49ef-8c6b-77306b3170d3</guid>
      <author>Andrew</author>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu</link>
      <category>Ruby on Rails</category>
      <category>cache_fu</category>
      <category>MemCached</category>
      <category>CachedModel</category>
      <category>rails</category>
      <category>rubyonrails</category>
      <category>performance</category>
      <category>cache</category>
      <category>caching</category>
      <trackback:ping>http://blog.onmylist.com/articles/trackback/15</trackback:ping>
    </item>
    <item>
      <title>"memcached and cache_fu" by Robert</title>
      <description>Your remove the 'Ruby-MemCache' solved my issue - its been a problem thats bugging me for ages. Thanks!</description>
      <pubDate>Wed, 13 Aug 2008 18:40:52 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:c82a93f9-4a81-4abc-9988-d31ffd60c6b3</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-27503</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by used tractors on ebay</title>
      <description>used tractors sales  on ebay.com</description>
      <pubDate>Thu, 10 Jul 2008 15:31:42 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:25410f09-c5db-485b-b98d-9d06e8fcb7a1</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-23863</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by viagra</title>
      <description>&lt;a href="http://cheapest-viagra.in" rel="nofollow"&gt;http://cheapest-viagra.in&lt;/a&gt;.
</description>
      <pubDate>Wed, 25 Jun 2008 06:15:48 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:8b7f0a3e-34ef-4c86-9f33-6fcc9870862e</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-22586</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by master@gmail.com</title>
      <description>I think this is an important story and would benefit from other NowPublic contributors working on it. I've flagged it as News Wanted and invite others in relevant locations to look for more evidence.  &lt;a href=" &lt;a href=" rel="nofollow"&gt;http://levitra-for-sale.com&lt;/a&gt; " alt="levitra"&gt;Cheap levitra. 
&lt;a href=" &lt;a href=" rel="nofollow"&gt;http://buying-cialis.net&lt;/a&gt; "&gt;Cialis pill. 
</description>
      <pubDate>Fri, 06 Jun 2008 10:29:36 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:e8253de7-67a9-4f10-aff2-c7a3c096be4d</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-20070</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by mmo</title>
      <description>Caching certainly does help reduce load times.</description>
      <pubDate>Mon, 21 Apr 2008 14:17:35 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:2aba60ef-c17e-42b9-a369-e50737c1ee53</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-14098</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by chase mahattan visa
</title>
      <description>I have quite a high credit rating and was careless enough to get several credit cards for which I was pre-approved by email. Now I realize they are too many and I was late with payments for 2 of them. Fortunately, I got a balance transfer credit card and moved the most part of my debt there, as I found the advice and the application form at
 
&lt;a href="http://best-creditcar.cn/mastercard-platinum-payment-center.html" rel="nofollow"&gt;http://best-creditcar.cn/mastercard-platinum-payment-center.html&lt;/a&gt; &gt;chase platinum mastercard payment center
 
chase unverisal
 
4a3s2d</description>
      <pubDate>Tue, 29 Jan 2008 22:17:37 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:e6507101-96f6-4956-9874-e62bfbe4287f</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-5164</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by Science</title>
      <description>You should consider EngineYard for Rails hosting as well - they're really good - I'm a customer but I don't get anything for saying good things about them.</description>
      <pubDate>Thu, 10 Jan 2008 17:22:02 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:2e10e2ce-caf1-4b4f-a50d-ee1dfa6f3816</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-3868</link>
    </item>
    <item>
      <title>"memcached and cache_fu" by evan</title>
      <description>This site was made to be a facebook application, no? I have no idea how to money-ma-tize that, but facebook applications are so hot right now.

Forgive the off topic comment. I didn't really know where else to give feedback.</description>
      <pubDate>Mon, 18 Jun 2007 21:18:47 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:586fcc20-dc3d-4e84-9042-a6b78f2ccf3b</guid>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu#comment-1</link>
    </item>
  </channel>
</rss>
