こんにちは
村上です。
ちょっと高速に読み書きできる共有ストレージが案件で必要になったので、KVSのmemcachedとredisを触ってみました。
インストール
どちらもyumでインストールできると思います。
| 1 2 | sudo yum install memcached sudo yum install redis | 
インストールが終わったら起動です。
| 1 2 | sudo /etc/init.d/memcached start sudo /etc/init.d/redis start | 
今回はどちらもRubyから操作します。
| 1 2 | gem install dalli gem install redis | 
ってして、もしくはGemfileに書いて「bundle install」 準備はOK
ちなみに「dalli」はmemcached用のgemです。
(読み方は「ダリ? ダルリ!?」)
memcached
まず、memcachedのdalliですが、こんな感じです。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | require 'dalli' dalli = Dalli::Client.new('localhost') dalli.set(:string, "hoge") # 文字列hogeをセット dalli.get(:string)         # 文字列を取得 dalli.set(:time, Time.now) # Timeをセット dalli.get(:time)           # Timeを取得。Timeオブジェクトで取得可能 dalli.set(:hash, {:a => "a", :b => "b"}) # ハッシュをセット dalli.get(:hash)                         # ハッシュを取得 ハッシュで取得可能 dalli.set(:array, ["1", "2", "3"])       # リストをセット dalli.get(:array)                        # リストを取得 リストで取得可能 dalli.set(:string, "hoge", 5) # 第3引数に整数をセット dalli.get(:string)            # 5秒間はデータ取り出し可能。5秒後にデータは削除される | 
redis
続いてredisですが、
| 1 2 3 4 5 6 7 8 9 | require 'redis' redis = Redis.new redis.set(:string, "hoge") # 文字列hogeをセット redis.get(:string)         # 文字列を取得 redis.set(:time, Time.now) # Timeをセット redis.get(:time)           # Timeを取得が文字列で取得される!! | 
ってことで、redisの場合は、オブジェクトは文字列となって取得されちゃいます。
なんで、下記のようなコンバートを実施
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | require 'redis' def encode(val)   Marshal.dump val end def decode(val)   Marshal.load val end redis.set(:string, encode("hoge")) # 文字列hogeをセット decode(redis.get(:string))         # 文字列を取得 redis.set(:time, encode(Time.now)) # Timeをセット decode(redis.get(:time))           # Timeを取得。Timeオブジェクトで取得可能 redis.set(:hash, encode({:a => "a", :b => "b"})) # ハッシュをセット decode(redis.get(:hash))                         # ハッシュを取得 ハッシュで取得可能 redis.set(:array, encode(["1", "2", "3"]))       # リストをセット decode(redis.get(:array))                        # リストを取得 リストで取得可能 | 
こんな感じでいけそうです。
あと、redisの場合は
| 1 2 | redis.setex(:string, 5, encode("hoge")) # 第2引数に整数をセット decode(redis.get(:string))              # 5秒間はデータ取り出し可能。5秒後にデータは削除される | 
にする必要があります。メソッドが変わって、dalliとは引数の場所が違うことに注意です。
decodeのメソッドですが、nilの場合はエラーになるので、nilを考慮した作りが必要です。
ちなみにnilをセットした時、動きが違いました。
| 1 2 3 4 5 6 7 8 9 10 11 12 | dalli.set(:nil, nil) # nilをセット dalli.get(:nil)      # nilが取得される。 redis.set(:nil, nil) # nilをセット dalli.get(:nil)      # 空文字が取得される redis.set(:nil, encode(nil)) # エンコードしてnilをセット decode(redis.get(:nil))      # デコードするとnilで取得可能 decode(nil)                  # これは上記の定義ではエラーが発生します。                              # nilの時はnilを返すような仕様にするか、                              # nil参照のエラーにするかはアプリ次第? | 
速度差
KVSなんで、高速の読み書きが求められます。
今回は3秒間でどれだけ読み書き(KVSへの値セットと値取得を1回ずつ行う)ができるかを測定します。
memcached
| 1 2 3 4 5 6 7 8 9 10 11 12 | count = 0 begin   timeout(3) {     loop {       dalli.set(count, count)       dalli.get(count)       count = count + 1     }   } ensure   p count end | 
redis
| 1 2 3 4 5 6 7 8 9 10 11 12 | count = 0 begin   timeout(3) {     loop {       redis.set(count, encode(count))       decode(redis.get(count))       count = count + 1     }   } ensure   p count end | 
結果は下記の通り
10回の平均です。
| 3秒間での読み書き回数 | |
|---|---|
| memcached | 19958.5 | 
| redis | 19627.5 | 
| redis コンバートなし | 20638.5 | 
| DB postgres | 956.5 | 
| ハッシュ | 3402237.3 | 
KVSだけではそれほど差がなかったので、DBとハッシュも比較対象に追加してみました。
今回はストレージがローカルにあるのでこの数字が出ましたが、ネットワーク越しにあれば、もう少し速度は低下すると思います。
速度は
メモリ > KVS > DB
でそれぞれ200倍ほどの差があるみたいですね。
当然ちゃ当然の結果ですが。
KVSを使うことがあれば参考にしてください。

 
						