<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="http://townx.org" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
 <title>townx - Ruby Tuesday: what I&amp;#039;ve learned about Rails and memcache - Comments</title>
 <link>http://townx.org/rails_and_memcached</link>
 <description>Comments for &quot;Ruby Tuesday: what I&#039;ve learned about Rails and memcache&quot;</description>
 <language>en</language>
<item>
 <title>Hi Manoel. I have to confess</title>
 <link>http://townx.org/rails_and_memcached#comment-14140</link>
 <description>&lt;p&gt;Hi Manoel. I have to confess to being at a loss here: without being in front of your set up it&#039;s hard to be able to see what&#039;s going on. You&#039;re using memcache-client (I take it), which I never messed with too much. There have also been a couple more versions since I did this testing, and I haven&#039;t done much with it since. Also looks like you&#039;re doing fragment caching to memcache too, which I never looked into. So I don&#039;t think I can be much help.&lt;/p&gt;

&lt;p&gt;One thing struck me, which is that &lt;tt&gt;:c_threshold =&amp;gt; 10_000&lt;/tt&gt; looks a bit suspect. Should the value be an integer?&lt;/p&gt;

&lt;p&gt;My other suggestion would be to strip the configuration down to its absolute minimum and get that working: the set up you have here looks quite complex. I&#039;d also suggest trying it with a non-memcached session store and making sure that works with Mongrel correctly. Might also be worth trying Ruby-Memcache (though I haven&#039;t looked at that for a while and am not sure if it is still a live project). And finally I had my memcache config. outside the Rails initializer block. I wonder if this has any effect?&lt;/p&gt;</description>
 <pubDate>Wed, 16 May 2007 10:37:51 -0500</pubDate>
 <dc:creator>elliot</dc:creator>
 <guid isPermaLink="false">comment 14140 at http://townx.org</guid>
</item>
<item>
 <title>Mongrel Cluster &amp; Memcached Sessions Issues: session is lost</title>
 <link>http://townx.org/rails_and_memcached#comment-14139</link>
 <description>&lt;p&gt;Gents,&lt;/p&gt;

&lt;p&gt;  I&#039;m having very strange issues in my setup:&lt;/p&gt;

&lt;p&gt;  front-end: 1 x apache + mod_proxy_balancer&lt;br /&gt;
  app servers: 12 x mongrels&lt;br /&gt;
  session store: 1 x memcached (512MB)&lt;/p&gt;

&lt;p&gt;  I configured both the local session date (stored on memcached) for 29&lt;br /&gt;
(seems that it cant be more than 30 days, this is a limitation of&lt;br /&gt;
memcached) days of expiration and the session cookies for one year of&lt;br /&gt;
expiration but my users still have to login again and again in very&lt;br /&gt;
short periods of time.&lt;/p&gt;

&lt;p&gt;  My environment.rb has:&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;
Rails::Initializer.run do |config|
  # Memcache Configuration
  memcache_options = {  :c_threshold =&amp;gt; 10_000,
                        :compression =&amp;gt; true,
                        :debug =&amp;gt; false,
                        :namespace =&amp;gt; &#039;mysite.com&#039;,
                        :readonly =&amp;gt; false,
                        :urlencode =&amp;gt; false }

  CACHE = MemCache.new(memcache_options)
  CACHE.servers = &#039;127.0.0.1:10001&#039;

  # Cache Storage Configuration
  config.action_controller.fragment_cache_store = CACHE, {}

  # Session Storage Configuration
  session_options = {   :cache =&amp;gt; CACHE,
                        :session_key =&amp;gt; &#039;_bbsession&#039;,
                        :session_domain =&amp;gt; &#039;.mysite.com&#039;,
                        :session_expires =&amp;gt; 3.months.from_now,
                        :expires =&amp;gt; 29.days }
  config.action_controller.session_store = :mem_cache_store
  ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(session_options)

end
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;  More, I tried to debug that and I could prove that after&lt;br /&gt;
leaving/closing the browser and opening it again (not entering the site&lt;br /&gt;
yet) both the local (memcached) and remote (cookies) session data is&lt;br /&gt;
available, but mongrels don&#039;t find them and then the user needs to login&lt;br /&gt;
again.&lt;/p&gt;

&lt;p&gt;  I&#039;m wondering if this is related to the load balancing or something&lt;br /&gt;
else.&lt;/p&gt;

&lt;p&gt;  Any ideas, suggestions?&lt;/p&gt;

&lt;p&gt;Manoel Lemos&lt;br /&gt;
Computer Engineer&lt;br /&gt;
Email: &lt;a href=&quot;mailto:manoel@lemos.net&quot;&gt;manoel@lemos.net&lt;/a&gt;&lt;/p&gt;</description>
 <pubDate>Tue, 15 May 2007 14:13:59 -0500</pubDate>
 <dc:creator>Manoel Lemos</dc:creator>
 <guid isPermaLink="false">comment 14139 at http://townx.org</guid>
</item>
<item>
 <title>Hello Sid. A few</title>
 <link>http://townx.org/rails_and_memcached#comment-14078</link>
 <description>&lt;p&gt;Hello Sid. A few thoughts:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;I&#039;d turn off memcache and check it works off the filesystem, first. Have you got it working without memcache?&lt;/li&gt;
&lt;li&gt;I&#039;m not familiar with this construction: &lt;tt&gt;(params[&#039;user&#039;][&#039;username&#039;][%r{[a-z]}i]).nil?&lt;/tt&gt;. What does it do in the context of this script?&lt;/li&gt;
&lt;li&gt;What does &lt;tt&gt;@user&lt;/tt&gt; contain by the time you get to &lt;tt&gt;redirect_to(:action=&amp;gt;&quot;home&quot;)&lt;/tt&gt;? Has it definitely been set with a value?&lt;/li&gt;
&lt;li&gt;What comes back from session[&#039;user&#039;] when you run &lt;tt&gt;find_user&lt;/tt&gt;?&lt;/li&gt;
&lt;li&gt;If you try to do a simple insert into session, then read out and reset (as per the example in my blog post), does that work? If it does, it looks like a problem with your script, not memcache or Ruby-memcache.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;It could be that the redirect works but that &lt;tt&gt;@user&lt;/tt&gt; is empty. Though I&#039;ve had another closer look and that seems impossible: you only get redirected to home if @user is not nil, so presumably it has some value, so it should be getting stored in the session. Mmm, perplexing!&lt;/p&gt;</description>
 <pubDate>Fri, 23 Mar 2007 11:23:00 -0500</pubDate>
 <dc:creator>elliot</dc:creator>
 <guid isPermaLink="false">comment 14078 at http://townx.org</guid>
</item>
<item>
 <title>Ruby-MemCache</title>
 <link>http://townx.org/rails_and_memcached#comment-14077</link>
 <description>&lt;p&gt;Elliot,&lt;/p&gt;

&lt;p&gt;Sure!! I have a :before_filter on :home which points to :session_auth&lt;/p&gt;

&lt;p&gt;The code:&lt;br /&gt;
require &quot;digest/sha1&quot;&lt;br /&gt;
def signin&lt;br /&gt;
    flag=0&lt;br /&gt;
    flag=1 if (params[&#039;user&#039;][&#039;username&#039;][%r{[a-z]}i]).nil? &lt;br /&gt;
    &lt;br /&gt;
    #If flag is set to 1 then match phone number else username&lt;br /&gt;
    if flag==1&lt;br /&gt;
      @user = User.find(:first, :conditions=&amp;gt;[&quot;phoneno = ? and hashed_password=?&quot;, params[&#039;user&#039;][&#039;username&#039;], Digest::SHA1.hexdigest(params[&#039;user&#039;][&#039;password&#039;])])&lt;br /&gt;
    else&lt;br /&gt;
      @user = User.find(:first, :conditions=&amp;gt;[&quot;username = ? and hashed_password=?&quot;, params[&#039;user&#039;][&#039;username&#039;], Digest::SHA1.hexdigest(params[&#039;user&#039;][&#039;password&#039;])])&lt;br /&gt;
    end  &lt;br /&gt;
  if @user.nil?&lt;br /&gt;
    flash[:notice] = &quot;Sign In Failed!&quot;&lt;br /&gt;
    redirect_to(:action=&amp;gt;&quot;login&quot;)&lt;br /&gt;
 else&lt;br /&gt;
    session[&#039;user&#039;] = @user&lt;br /&gt;
    redirect_to(:action=&amp;gt;&quot;home&quot;)&lt;br /&gt;
  end&lt;br /&gt;
  end&lt;/p&gt;

&lt;p&gt;  def find_user&lt;br /&gt;
  session[&#039;user&#039;]&lt;br /&gt;
  end&lt;br /&gt;
  &lt;/p&gt;

&lt;p&gt;  def session_auth&lt;br /&gt;
  @user = find_user&lt;br /&gt;
  if @user.nil?&lt;br /&gt;
    flash[:notice]=&quot;Your Session Has Expired!&quot;&lt;br /&gt;
    redirect_to(:controller=&amp;gt;&quot;top&quot;, :action=&amp;gt;&quot;error&quot;)  &lt;br /&gt;
  end&lt;br /&gt;
  end&lt;/p&gt;

&lt;p&gt;In the :session_auth function the session is completely blank. I removed the filter and let the redirect continue to :home but the session was still blank. Other than that the before and after example on the main page works perfectly.&lt;br /&gt;
I even thought that maybe putting an object into the session variable isn&#039;t such a good idea, simple strings also get flushed :(&lt;br /&gt;
Sid.&lt;/p&gt;</description>
 <pubDate>Thu, 22 Mar 2007 10:43:08 -0500</pubDate>
 <dc:creator>Sid</dc:creator>
 <guid isPermaLink="false">comment 14077 at http://townx.org</guid>
</item>
<item>
 <title>Hello Sid. Without seeing</title>
 <link>http://townx.org/rails_and_memcached#comment-14076</link>
 <description>&lt;p&gt;Hello Sid. Without seeing the specifics of the code, it&#039;s hard to debug. If you&#039;ve got a code snippet I can try out myself (providing your application isn&#039;t so horrendously complicated you can&#039;t send one) I&#039;d be happy to have a look over it. Have you made sure it&#039;s not the session[&#039;logged_in&#039;] vs. session[:logged_in] thing, or something like it? Can you see what&#039;s happening on the client and inside memcache? Do the sessions work without memcache?&lt;/p&gt;</description>
 <pubDate>Thu, 22 Mar 2007 10:15:00 -0500</pubDate>
 <dc:creator>elliot</dc:creator>
 <guid isPermaLink="false">comment 14076 at http://townx.org</guid>
</item>
<item>
 <title>Ruby-MemCache</title>
 <link>http://townx.org/rails_and_memcached#comment-14073</link>
 <description>&lt;p&gt;Hi,&lt;/p&gt;

&lt;p&gt;I&#039;m using Ruby-MemCache and I have the same problem. It&#039;s not just about filters though, a redirect_to somehow manages to come up with a blank session. Any thoughts?&lt;br /&gt;
cheers,&lt;br /&gt;
Sid.&lt;/p&gt;</description>
 <pubDate>Thu, 22 Mar 2007 06:44:02 -0500</pubDate>
 <dc:creator>Sid</dc:creator>
 <guid isPermaLink="false">comment 14073 at http://townx.org</guid>
</item>
<item>
 <title>Glad you sorted it. Comments</title>
 <link>http://townx.org/rails_and_memcached#comment-14047</link>
 <description>&lt;p&gt;Glad you sorted it. Comments are always welcome, even though it&#039;s not a forum. I&#039;ve had that string vs. symbol before. Most irritating.&lt;/p&gt;</description>
 <pubDate>Fri, 09 Mar 2007 03:46:41 -0600</pubDate>
 <dc:creator>elliot</dc:creator>
 <guid isPermaLink="false">comment 14047 at http://townx.org</guid>
</item>
<item>
 <title>uhh... never mind</title>
 <link>http://townx.org/rails_and_memcached#comment-14045</link>
 <description>&lt;p&gt;i know this isnt a forum, but the issue was sybols vs. strings with memcache-client. session[;user_id] is not something that memcache can sustain... session[&#039;user_id&#039;].  Lame.&lt;/p&gt;

&lt;p&gt;n&lt;/p&gt;</description>
 <pubDate>Thu, 08 Mar 2007 15:32:36 -0600</pubDate>
 <dc:creator>Guest</dc:creator>
 <guid isPermaLink="false">comment 14045 at http://townx.org</guid>
</item>
<item>
 <title>sessions breaking when logging in to private area</title>
 <link>http://townx.org/rails_and_memcached#comment-14044</link>
 <description>&lt;p&gt;I was wondering if you have encountered memcahced not being able to maintain a logged in status in a simple admin/private area. I have not changed my code from moving from files to memcache, your tutorial code works, but i am getting kicked out of my before_filer :make_sure_logged_in area.  Thanks in advance.&lt;/p&gt;

&lt;p&gt;n&lt;/p&gt;</description>
 <pubDate>Thu, 08 Mar 2007 14:59:56 -0600</pubDate>
 <dc:creator>Guest</dc:creator>
 <guid isPermaLink="false">comment 14044 at http://townx.org</guid>
</item>
<item>
 <title>Ruby Tuesday: what I&#039;ve learned about Rails and memcache</title>
 <link>http://townx.org/rails_and_memcached</link>
 <description>&lt;p&gt;&lt;a href=&quot;http://www.danga.com/memcached/&quot;&gt;memcached&lt;/a&gt; is the cool new thing people are using to store Rails sessions and cache models. To quote the website:&lt;/p&gt;

&lt;blockquote&gt;&quot;memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.&lt;/blockquote&gt;

&lt;p&gt;What that basically means is that you can run memcached on one or multiple servers, and they are bundled together to present one big key store you can write values into or read values out of. The key store is volatile, in that it sits in memory: if all the memcache servers fall over, all the data stored in them is lost. But this is fine for caching and sessions. In the case of Rails&#039; use of memcache, the session object itself is marshalled and written into the key store when a session value is added or updated; and the same key is used to retrieve the session data.&lt;/p&gt;

&lt;p&gt;The main reason for using memcached is so you have a single session store which can be written to and read from multiple Mongrel instances. If you&#039;re running a Mongrel cluster, this means a client can be served by any member of the cluster, and all the Mongrel instances have access to the client&#039;s session.&lt;/p&gt;

&lt;p&gt;In the rest of this article, I&#039;ll go through:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;How to install memcached (the daemon which runs memcache instances) on Ubuntu Linux&lt;/li&gt;
&lt;li&gt;How to install the Ruby libraries for talking to memcached&lt;/li&gt;
&lt;li&gt;How to configure your Rails application to use memcached for sessions&lt;/li&gt;
&lt;li&gt;Some benchmarking I&#039;ve done on the various Ruby memcache libraries&lt;/li&gt;
&lt;li&gt;A plugin I&#039;ve written to help an app. recover if memcached disappears&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;I won&#039;t be covering:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;How to configure memcached as a service&lt;/li&gt;
&lt;li&gt;How to cache models into memcached&lt;/li&gt;
&lt;li&gt;How to secure memcached and mongrel&lt;/li&gt;
&lt;li&gt;How to setup a Mongrel cluster (I might cover this another day, but not now)&lt;/li&gt;
&lt;/ul&gt;



&lt;h2&gt;memcached installation&lt;/h2&gt;

&lt;p&gt;memcached is packaged for Ubuntu Breezy, so I just did:&lt;/p&gt;



&lt;pre&gt;
apt-get install memcached
&lt;/pre&gt;



&lt;p&gt;I then started a memcached instance as non-root with:&lt;/p&gt;



&lt;pre&gt;
memcached -d -l 127.0.0.1 -p 17898 -m 256 -P /tmp/memcached.pid
&lt;/pre&gt;



&lt;p&gt;The flags mean:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;-d = run as a daemon&lt;/li&gt;
&lt;li&gt;-l &amp;lt;ip address&amp;gt; = bind to ip address&lt;/li&gt;
&lt;li&gt;-p &amp;lt;port&amp;gt; = run on this port&lt;/li&gt;
&lt;li&gt;-m &amp;lt;num&amp;gt; = use num Mb of memory for the store&lt;/li&gt;
&lt;li&gt;-P = where to put the pid file&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;When you&#039;re debugging, it&#039;s useful to use this variant instead, which makes it extra verbose and doesn&#039;t daemonize:&lt;/p&gt;



&lt;pre&gt;
memcached -vv -l 127.0.0.1 -p 17898 -m 256 -P /tmp/memcached.pid
&lt;/pre&gt;



&lt;h2&gt;Ruby memcached bindings installation&lt;/h2&gt;

&lt;p&gt;There is some debate about which of the Ruby libraries is best for use with memcached. I&#039;ve formed my own opinion after some very basic testing, but I&#039;ll explain both before we get to that.&lt;/p&gt;

&lt;p&gt;The two choices are:&lt;/p&gt;


&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;memcache-client&lt;/strong&gt; from &lt;a href=&quot;http://rubyforge.org/projects/rctools/&quot; title=&quot;http://rubyforge.org/projects/rctools/&quot;&gt;http://rubyforge.org/projects/rctools/&lt;/a&gt;. This is the one everyone says is fastest. It is quite basic and difficult to debug.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ruby-MemCache&lt;/strong&gt; from &lt;a href=&quot;http://www.deveiate.org/projects/RMemCache/&quot; title=&quot;http://www.deveiate.org/projects/RMemCache/&quot;&gt;http://www.deveiate.org/projects/RMemCache/&lt;/a&gt;. This is older but (to my mind) has better error correction and debugging information.&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;Installation can be done from a gem. For memcache-client:&lt;/p&gt;



&lt;pre&gt;
gem install memcache-client -v 1.0.3
&lt;/pre&gt;



&lt;p&gt;Note that I&#039;ve specified this version because the current version (1.1.0) doesn&#039;t appear to work properly on my machine. This is because the threading code has been substantially rewritten, but some of the checks for whether to use multithreading have not been applied correctly (see &lt;a href=&quot;http://rubyforge.org/tracker/index.php?func=detail&amp;amp;aid=5994&amp;amp;group_id=1266&amp;amp;atid=4981&quot;&gt;this bug report&lt;/a&gt;). So I&#039;d stick with version 1.0.3 if I were you.&lt;/p&gt;

&lt;p&gt;For Ruby-MemCache:&lt;/p&gt;



&lt;pre&gt;
gem install Ruby-MemCache
&lt;/pre&gt;



&lt;p&gt;By the way, I wouldn&#039;t recommend installing both at the same time: they appear to tread all over each other&#039;s namespaces, so I never felt confident that I knew which was being loading when I did my testing.&lt;/p&gt;

&lt;h2&gt;Setting up a Rails testing application&lt;/h2&gt;

&lt;p&gt;Regardless of which memcached client library you are using, the Rails configuration is the same, and is done in environment.rb. For testing, I set up a new Rails project called &lt;strong&gt;mem&lt;/strong&gt;: &lt;/p&gt;



&lt;pre&gt;
rails mem
&lt;/pre&gt;



&lt;p&gt;I then created a controller for my testing:&lt;/p&gt;



&lt;pre&gt;
cd gem
script/generate controller Sess
&lt;/pre&gt;



&lt;p&gt;And put this content into app/controllers/sess_controller.rb:&lt;/p&gt;



&lt;pre&gt;
class SessController &amp;lt; ApplicationController
  def index
    @before_id = session[&#039;id&#039;]
    session[&#039;id&#039;] = Time.now
  end
end
&lt;/pre&gt;



&lt;p&gt;This tries to read something out of the session, then resets it. This enables you to test both read and write operations.&lt;/p&gt;

&lt;p&gt;I then added a view in app/views/sess/index.rhtml to show what&#039;s in the session:&lt;/p&gt;



&lt;pre&gt;
&amp;lt;p&amp;gt;Before: &amp;lt;%= @before_id %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;After: &amp;lt;%= session[&#039;id&#039;] %&amp;gt;&amp;lt;/p&amp;gt;
&lt;/pre&gt;



&lt;p&gt;Remember this isn&#039;t a brilliantly-written application with valid &lt;span class=&quot;caps&quot;&gt;HTML, &lt;/span&gt;just a piece of junk to test sessions with.&lt;/p&gt;

&lt;p&gt;I then edited environment.rb so that ActiveRecord doesn&#039;t load (I&#039;m not going to be using a database, as this just complicates things). Find this line:&lt;/p&gt;



&lt;pre&gt;
#config.frameworks -= [ :action_web_service, :action_mailer ]
&lt;/pre&gt;



&lt;p&gt;and edit it to look like this instead:&lt;/p&gt;



&lt;pre&gt;
config.frameworks -= [ :active_record, :action_web_service, :action_mailer ]
&lt;/pre&gt;



&lt;p&gt;Now we&#039;re ready to test whether sessions work in the default fashion, and check our application is OK:&lt;/p&gt;



&lt;pre&gt;
mongrel_rails start -e production
&lt;/pre&gt;



&lt;p&gt;Notice that I&#039;ve used the production environment throughout as this speeds things up somewhat. Now browse to &lt;strong&gt;http://localhost:3000/sess/&lt;/strong&gt; and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/memcache_app.png&quot; alt=&quot;&quot; height=&quot;428&quot; width=&quot;543&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The top line is blank as there&#039;s nothing in the session, and we&#039;re trying to print something from it. Refresh the page and you should get the value set on the previous request. This is how you know sessions are working.&lt;/p&gt;

&lt;h2&gt;Switching sessions to use memcached&lt;/h2&gt;

&lt;p&gt;Now we&#039;re going to switch session management over to memcached, instead of the default file-based sessions system. Let&#039;s get memcached started in debug mode:&lt;/p&gt;



&lt;pre&gt;
$ memcached -vv -l 127.0.0.1 -p 17898 -m 256 -P /tmp/memcached.pid
&amp;lt;3 server listening
&lt;/pre&gt;



&lt;p&gt;Notice the second line, which shows memcached listening on the specified port.&lt;/p&gt;

&lt;p&gt;Stop the Rails application, then edit environment.rb. First find this line:&lt;/p&gt;



&lt;pre&gt;
# config.action_controller.session_store = :active_record_store
&lt;/pre&gt;



&lt;p&gt;and edit it to look like this:&lt;/p&gt;



&lt;pre&gt;
config.action_controller.session_store = :mem_cache_store
&lt;/pre&gt;



&lt;p&gt;Next, add this line to the top of the file (before the &lt;code&gt;Rails::Initializer.run do |config|&lt;/code&gt; line):&lt;/p&gt;



&lt;pre&gt;
require_gem &#039;Ruby-MemCache&#039;
&lt;/pre&gt;



&lt;p&gt;I&#039;m using Ruby-MemCache here, but you could do &lt;code&gt;require_gem &#039;memcache-client&#039;&lt;/code&gt; if you prefer. I require the gems rather than the libraries because this makes it clear which library I&#039;m using.&lt;/p&gt;

&lt;p&gt;Then add these lines at the bottom:&lt;/p&gt;



&lt;pre&gt;
memcache_options = {
   :compression =&amp;gt; true,
   :debug =&amp;gt; false,
   :namespace =&amp;gt; &amp;quot;mem-#{RAILS_ENV}&amp;quot;,
   :readonly =&amp;gt; false,
   :urlencode =&amp;gt; false
}

memcache_servers = [ &#039;127.0.0.1:17898&#039; ]

CACHE = MemCache.new(memcache_options)
CACHE.servers = memcache_servers
ActionController::Base.session_options[:cache] = CACHE
&lt;/pre&gt;



&lt;p&gt;The memcache_options are reasonably self-explanatory, but just for clarity:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;compression: use compression when communicating with memcached&lt;/li&gt;
&lt;li&gt;namespace: store keys for this application inside this &quot;chunk&quot; of the memcache&lt;/li&gt;
&lt;li&gt;readonly: allow writes into the memcache&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;The memcache_servers array should list all of the host/IP address combinations for your memcache servers. We&#039;ve only got one on localhost, hence our setting.&lt;/p&gt;

&lt;p&gt;The last three lines make the new memcache instance available to our controllers.&lt;/p&gt;

&lt;h2&gt;The moment of truth&lt;/h2&gt;

&lt;p&gt;Restart your application in a new console (remember to leave memcached running):&lt;/p&gt;



&lt;pre&gt;
mongrel_rails start -e production
&lt;/pre&gt;



&lt;p&gt;Browse to &lt;strong&gt;http://localhost:3000/sess/&lt;/strong&gt;. You should see something similar to last time (see the image above). Refresh the page, and you should see that both the &lt;strong&gt;Before&lt;/strong&gt; and &lt;strong&gt;After&lt;/strong&gt; paragraphs include a time.&lt;/p&gt;

&lt;p&gt;Now check your memcached instance in the other console window, and you should see something like this:&lt;/p&gt;



&lt;pre&gt;
&amp;lt;7 new client connection
&amp;lt;7 get mem-production:session:0121026304505352eceeb4d82d849433
&amp;gt;7 END
&amp;lt;7 set mem-production:session:0121026304505352eceeb4d82d849433 1 0 81
&amp;gt;7 STORED
&lt;/pre&gt;



&lt;p&gt;This indicates that Rails is correctly storing session data into memcached. Hurrah!&lt;/p&gt;

&lt;h2&gt;Benchmarking&lt;/h2&gt;

&lt;p&gt;I was quite interested in the suppose performance differences between memcache-client and Ruby-MemCache. Bear in mind the application is a toy one, it doesn&#039;t have a database, and is very simple. (Though these could be considered strengths, as it&#039;s taking a lot out of the equation.) Anyway, I ran some testing on the two different libraries, as shown in the table below. Here&#039;s my setup:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;Mongrel 0.3.13.4&lt;/li&gt;
&lt;li&gt;Rails 1.1.6&lt;/li&gt;
&lt;li&gt;memcached 1.1.12&lt;/li&gt;
&lt;li&gt;Ruby-MemCache 0.0.1&lt;/li&gt;
&lt;li&gt;memcache-client 1.0.3&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;I ran the application in production mode, using one of the two libraries; I used no debugging on Mongrel or on the memcache libraries. I used ab for the benchmarking, with this command:&lt;/p&gt;



&lt;pre&gt;
ab -n2000 -c20  &lt;a href=&quot;http://localhost:3000/sess/&quot; title=&quot;http://localhost:3000/sess/&quot;&gt;http://localhost:3000/sess/&lt;/a&gt;
&lt;/pre&gt;



&lt;p&gt;(2000 requests, concurrency of 20.)&lt;/p&gt;

&lt;p&gt;Here are the results:&lt;/p&gt;

&lt;table&gt;&lt;tr&gt;&lt;td&gt;Library&lt;/td&gt;&lt;td&gt;Total time for 2000 requests (seconds)&lt;/td&gt;&lt;td&gt;Mean time per request (ms)&lt;/td&gt;&lt;td&gt;Requests per second&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ruby-MemCache&lt;/td&gt;&lt;td&gt;36.310&lt;/td&gt;&lt;td&gt;18.155&lt;/td&gt;&lt;td&gt;55.08&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;memcache-client&lt;/td&gt;&lt;td&gt;31.787&lt;/td&gt;&lt;td&gt;15.894&lt;/td&gt;&lt;td&gt;62.92&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;In both cases, all 2000 requests were served without error. You can see that memcache-client is faster, but not much.&lt;/p&gt;

&lt;h2&gt;And here my curiosity got the better of me&lt;/h2&gt;

&lt;p&gt;I like breaking things. So I decided to see what happens if you switch off memcached: how does the Rails application respond? Can it carry on serving pages? Can it recover? What happens to sessions? I know it&#039;s unlikely that memcached would disappear completely from anyone&#039;s setup, as it is distributed, and likely to run across multiple machines. But what if the server network cable got unplugged or the card broke? Or you only had two memcached servers and they both broke simultaneously?&lt;/p&gt;

&lt;p&gt;So I tried running my application, then switching memcached off. The results were quite interesting:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;Rails with &lt;strong&gt;memcache-client&lt;/strong&gt; just falls over. Once memcached is down, the connection is lost and isn&#039;t recovered. This causes the whole Rails application to crash and serve only 500 error pages.&lt;/li&gt;
&lt;li&gt;Rails with &lt;strong&gt;Ruby-MemCache&lt;/strong&gt; continues to serve the application, but sessions are irretrievably broken.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;In both cases, if you restart memcached, the application can&#039;t pick up the connection again until you restart Mongrel. This also means that before you start your app., memcached must be running and available, otherwise your application won&#039;t start correctly. Of the two, Ruby-MemCache obviously offers the nicest end result, as at least it doesn&#039;t fall over.&lt;/p&gt;

&lt;h2&gt;Respawning connections to memcached&lt;/h2&gt;

&lt;p&gt;I decided a decent solution might be to monitor the memcached instances from Rails and ensure that there is at least one available. If none is available, attempt to respawn the connection; keep doing this until it is re-established. This adds some overhead (checking memcached is &lt;span class=&quot;caps&quot;&gt;OK, &lt;/span&gt;respawning if not), but could be worth it where memcached is not highly distributed, or the network is unpredictable.&lt;/p&gt;

&lt;p&gt;To this end, I&#039;ve bundled together a plugin which will monitor memcached. While Ruby-MemCache monitors memcached servers, memcache-client doesn&#039;t. Consequently, this code only works with Ruby-MemCache.&lt;/p&gt;

&lt;p&gt;To use it:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;Unzip the zip file below and drop the resulting folder into vendor/plugins.&lt;/li&gt;
&lt;li&gt;Edit environment.rb and change the bottom part of the file (where you set up MemCache) to this instead:&lt;/li&gt;
&lt;/ul&gt;





&lt;pre&gt;
MEMCACHE_OPTIONS = {
   :compression =&amp;gt; true,
   :debug =&amp;gt; false,
   :namespace =&amp;gt; &amp;quot;mem-#{RAILS_ENV}&amp;quot;,
   :readonly =&amp;gt; false,
   :urlencode =&amp;gt; false
}

MEMCACHE_SERVERS = [ &#039;127.0.0.1:17898&#039; ]

CACHE = MemCache.new(MEMCACHE_OPTIONS)
CACHE.servers = MEMCACHE_SERVERS
MEMCACHE_MONITORING = true
ActionController::Base.session_options[:cache] = CACHE
&lt;/pre&gt;



&lt;p&gt;Note I&#039;ve changed the option settings into constants (so the MemCache options can be accessed by the plugin), and added a &lt;span class=&quot;caps&quot;&gt;MEMCACHE&lt;/span&gt;_MONITORING variable, which toggles monitoring (set to false to disable the monitoring code). To test it:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;Start memcached, then Mongrel.&lt;/li&gt;
&lt;li&gt;Check your sessions are working and Rails can access memcached.&lt;/li&gt;
&lt;li&gt;Stop memcached. Your sessions should now stop working, while the app. still gets served.&lt;/li&gt;
&lt;li&gt;Restart memcached. Sessions should be re-established.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Enjoy! Any comments welcome as always.&lt;/p&gt;

&lt;p&gt;The plugin adds some overhead, but not much: I&#039;ll put some stats. up shortly.&lt;/p&gt;</description>
 <comments>http://townx.org/rails_and_memcached#comments</comments>
 <category domain="http://townx.org/tech">tech</category>
 <category domain="http://townx.org/howtos">howtos</category>
 <enclosure url="http://townx.org/files/mem_cache_monitor.zip" length="2561" type="application/zip" />
 <pubDate>Tue, 03 Oct 2006 04:11:53 -0500</pubDate>
 <dc:creator>elliot</dc:creator>
 <guid isPermaLink="false">412 at http://townx.org</guid>
</item>
</channel>
</rss>
