続Memcache

RubyのMemcacheを検証しているがマルチサーバーになったときに自動的にコネクションを切り捨てる機能はどうやらなさそう。

値がとれなかった時に、サーバーを切り捨てるラッパーを作ろうと想ったんだが、どうも動きが読めない

  1. 最初からサーバーがつながってないとき
  2. 途中で片方が切れたとき
  3. 途中で両方切れたとき

3パターンぐらいかなとおもってたら、どうも状況に応じて戻ってくるエラーがいつも異なる。うーん、どうしたもんかなあ。これだとうまくラッパーが書けないや。

というわけでいろいろ調べてみた。どうもライブラリの挙動がおかしい。memcache-clientの1.5.0には以下のバグがありそう。

まず、2つのMemcachedサーバーに接続しているときに途中でわざと片方を落としてエラーをひろって残りに接続するサンプルを書いてみる。

 #!/usr/local/bin/ruby1.8
 
 require "rubygems"
 require "memcache"
 require "ruby-debug"
 cache = MemCache.new(["192.168.0.1","192.168.0.2"])
 
 begin
   while(true) do
     cache["data"+rand(1199999).to_s] = 22
   end
 rescue MemCache::MemCacheError
   cache.servers =  cache.servers.find_all{|sv| true == sv.alive?}
 end
 
 p cache["comeon"] = "successfule"

こんな感じ。MemCache::MemCacheErrorでエラーを検出したら、serversで接続先を拾い出してalive?がtrueの物を配列にして元に戻す。

これでばっちり再接続できそうな感じだが、これだとエラーが出て動かない。

 /memcache.rb:166:in `servers=': undefined method `memcache' for 
     :MemCache::Server (NoMethodError)

こんなエラーがでる。はて?memcacheっていう名前のメソッドがMemCache::Serverに定義されてないとな?該当箇所を調べてみる。

memcache.rbの166行目

 if server.memcache.multithread != @multithread then

やっぱり(悲)。MemCache::Serverクラスにmemcacheクラスはいまないのよね。マルチスレッドのチェックをしているみたいだから、使わないのであれば、166〜168行目をコメントアウトすることで動作する。

ただ、ライブラリに手をいれるのは好きじゃないので回避するトリックを考えてみた。

 require "rubygems"
 require "memcache"
 require "ruby-debug"
 cache = MemCache.new(["192.168.0.1","192.168.0.2"])
 
 begin
   while(true) do
     cache["data"+rand(1199999).to_s] = 22
   end
 rescue MemCache::MemCacheError
 #  動作できないのでコメントアウト
 #  cache.servers =  cache.servers.find_all{|sv| true == sv.alive?}
 
 #一端別のオブジェクトにデータを移しておいて、
 #<<で自力で追加してやるのであれば、MemCacheのメソッドを利用してないので、挿入できる。
    doc =  cache.servers.find_all{|sv| true == sv.alive?}
    cache.servers = []
    doc.each do |i|
      cache.servers << i
    end
 end
 
 p cache["comeon"] = "successfule"

これでOK。ループの途中でmemcachedサーバーを片方切断しても自動的に接続構成を切り替えて最後の行まで流れる。

これを自動的に行うラッパークラスを作ればいけるな。

もうちょっと粘ってみよう。