Railsとelasticache(memcached)について


はじめに

Railsで、elasticache(memcached)を使ったときに調べたことについて書いてみた

Railsでelasticacheを使うには?

dalli-elasticacheがある。4年位更新されてないけど、依存しているgemがdalliだけで、elasticache自体の仕様も殆ど変わっていないので未だに使える。
役割自体も、設定エンドポイントからクラスターに所属するホストの一覧を取得して、dalliに渡していい感じに初期化しているだけなのでシンプル。

設定エンドポイントとは?

elasticache memcachedクラスターの代表となるエンドポイント

どうやってノードを取得しているか?

ノードの取得方法は、dalli-elasticacheが設定エンドポイントに対して、専用のコマンドを投げることによってノードの一覧を取得している。下記が実際にやってみたサンプル

[root@hoge ~]# echo 'config get cluster' | nc -v hoge.fgjtnh.cfg.apne1.cache.amazonaws.com 11211
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 10.13.48.xxx:11211.
CONFIG cluster 0 174
3
hoge.fgjtnh.0001.apne1.cache.amazonaws.com|10.13.48.xxx|11211 hoge.fgjtnh.0002.apne1.cache.amazonaws.com|10.13.10.xxx|11211

END
Ncat: 19 bytes sent, 203 bytes received in 0.01 seconds.

※実際にやってみるてわかったが、各ノードに同じコマンドを送っても同様のものを取得することができた。

クラスターにはどのようにキーが格納されているか?

クラスターといっても実際には複数のノードにシャーディングされているだけなので、各ノード間でレプリケーションされているわけではない。
なのでそれぞれの値は、クラスターに所属するノードに独立して保存されている。どのノードに保存するかはdalliが格納/検索するときのキーからノードを決定している。
dalliを経由せずにtelnetなどで直接値を取得する場合は、全サーバーにキーを問い合わせてみる必要がある。
これは結構めんどくさいし、代表エンドポイントに問い合わせてもいずれかのノードに聞いてくれるだけなので、キーがあったりなかったりするので注意が必要。

dalliはどのように格納するノードを決めているか?

dalli gem自体で、複数のmemcachedを扱うことが出来るようになっている
複数のmemcached(ノード群)は初期化時に登録される。
どのノードに格納するかは、キーを元に算出するようになっている
下記が決定に使われているメソッド(コード)

    def server_for_key(key)
      if @continuum
        hkey = hash_for(key)
        20.times do |try|
          # Find the closest index in the Ring with value <= the given value
          entryidx = @continuum.bsearch_index { |entry| entry.value > hkey }
          if entryidx.nil?
            entryidx = @continuum.size - 1
          else
            entryidx -= 1
          end
          server = @continuum[entryidx].server
          return server if server.alive?
          break unless @failover
          hkey = hash_for("#{try}#{key}")
        end
      else
        server = @servers.first
        return server if server&.alive?
      end

memcachedの各ノードからキー一覧を取得するには?

slabの番号をまず取得した上で、stats cachedumpでslabごとにキーを取得する必要がある。

export LIMIT=0
export MEMCACHED_HOST=memcache.apne1.cache.amazonaws.com

echo 'stats slabs' | nc $MEMCACHED_HOST 11211  | grep ':' | awk -F '[ :]' '{ print $2 }' | sort -u\
  | xargs -n 1 -I '{}' bash -c 'echo "stats cachedump {} $LIMIT" | nc  $MEMCACHED_HOST 11211'

各コマンドの説明は下記

  • stats slabs : memcachdの記憶領域であるslabsの統計を表示するコマンド、このコマンドを使用してノードに存在する全slabの番号を取得している
  • stats cachedump : slabに所属するキーの一覧を表示するコマンド、引数にslabの番号と取得数を指定する、0を指定した場合はすべて出力される

まとめ

というわけで、Railsでelasticache(memcached)を使ったときのことを書いてみた。
そもそもelasticacheのクラスターについて知らなくて、格納されているキーを探すのも一苦労だった。まずは敵を知ることの大切さがわかった。