key-value ストアに興味がある ささたつ です。key-value ストアとして有名なものといえば memcached かと思いますが、他にも TokyoCabinet や TokyoTyrant というものも注目されています(不思議な名前ですね!)。key-value ストアでありながら高速、かつ、データをメモリで無くファイルに保存しているため、サーバが落ちてもデータが消えないとか。

実際に mixi の最終ログイン時間の保持などに使われているそうです。

memcached をセッションの保持などに使っている場合、memcached のサーバがダウンしてしまったら、データは全て消えてしまいます。その結果 RDBMS にアクセスが集中し、パフォーマンスが大幅に悪化してしまう(最悪の場合、アクセス不能になる)でしょう。そのようなケース(データのやり取りに高速性が求められる、かつ、データが消えては困るような場合)では memcached 並に高速かつ、データが消えない TokyoCabinet/TokyoTyrant が非常に使えるのではないかと思います。

ところで、名前が似ていてわかりにくいですが、TokyoCabinet が key-valueストアの機能を持っていて、データを保存したり、取り出したり出来ます。TokyoTyrant は TokyoCabinet をネットワーク越しに操作できるようにしたラッパーです。キャビネット(内閣)を傀儡にするタイラント(僭主)ということでこのような名前が付けられたそうですw

TokyoCabinet では、データの保存方法が色々選べます。例えばこのようなものがあります。

ハッシュデータベース  # 1 つの key に対して 1 つの value を持つ
B+-tree データベース  # 同じ key に対して複数のレコードを格納できる
テーブルデータベース  # 特定の key に対して複数の値を保持できる

今回はこの中で最も一般的な key-value ストアの特徴を持っている(つまり、ハッシュテーブル構造の)『ハッシュデータベース』を試してみます。

TokyoTyrant/TokyoTyrant のインストール

ソースは こちら にあります。今回は Ruby を使って TokyoCabinet/TokyoTyrant を扱うため、以下の 4 つをインストールしました。現時点での最新版です。

・tokyocabinet-1.4.9.tar.gz
・tokyocabinet-ruby-1.9.tar.gz
・tokyotyrant-1.1.9.tar.gz
・tokyotyrant-ruby-1.9.tar.gz

TokyoCabinet
tar zxvf tokyocabinet-1.4.9.tar.gz
cd tokyocabinet-1.4.9
./configure
make
sudo make install

TokyoCabinet Ruby API
tar zxvf tokyocabinet-ruby-1.9.tar.gz
cd tokyocabinet-ruby-1.9
ruby extconf.rb
make
sudo make install

TokyoTyrant
tar zxvf tokyotyrant-1.1.9.tar.gz
cd tokyotyrant-1.1.9
./configure
make
sudo make install

TokyoTyrant Ruby API
tar zxvf tokyotyrant-ruby-1.9.tar.gz
cd tokyotyrant-ruby-1.9
sudo ruby install.rb

Ruby バインディングの TokyoCabinet を使ってみる

まずは TokyoCabinet を試してみます。TokyoCabinet を単体で使うと、ローカルでの key-value ストアとして、ハッシュ構造のデータを扱えます。

#!/usr/bin/ruby

require 'tokyocabinet'
include TokyoCabinet

hdb = HDB.new # ハッシュデータベースを指定

hdb.tune(131071, 4, 10, 0) # 初期設定
hdb.open('tc.hdb', HDB::OWRITER | HDB::OCREAT) # データの保存先指定など

hdb.put('hoge', 'fuga') # key: hoge, value: fuga
p hdb.get('hoge')       # fuga が返ってくる

hdb.close

もしうまく動かず、

/usr/local/lib/libtokyocabinet.so: libtokyocabinet.so.8: 
cannot open shared object file: No such file or directory

のようなエラーが出てきた場合には、/etc/ld.so.conf に /usr/local/lib を追加して、以下のコマンドを実行してください。/etc/ld.so.cache が更新され、共有ライブラリが見つかるようになるはずです。

sudo /sbin/ldconfig

Ruby バインディングの TokyoTyrant を使ってみる

さぁ、次は TokyoTyrant を試してみます。まず始めに TokyoTyrant のサーバを起動します。デフォルトでは 1978 番ポートで待ち受けます。

sudo /usr/local/sbin/ttservctl start

#!/usr/bin/ruby -Ku

require 'tokyotyrant'
include TokyoTyrant
 
rdb = RDB::new
rdb.open('localhost', 1978)

rdb.put('hoge', 'タマ')
p rdb.get('hoge') # 'タマ'

rdb.close

おぉ〜、無事動きました。ただ、TokyoCabinet のときと違って、何も初期設定(データの保存先など)を行っていないような気が、、。と思ったら、/usr/local/sbin/ttservctl の中に設定が直書きされているみたいです。データファイルは /var/ttserver ディレクトリに作成されます。

ここでは、TokyoTyrant 独自プロトコルで扱っていますが、他にも HTTP や memcached 互換のプロトコルでも扱うことが出来ます(ただし、有効期限はサポートしていない)。そのため、今まで memcached を使っていて、TokyoTyrant に変更する場合、この程度の変更で対応できることも大きな魅力です。

# memcached の場合
MemCache::new 'localhost:11211'

# TokyoTyrant の場合
MemCache::new 'localhost:1978' # ポートの変更だけでおk

あと、本当にサーバがダウンしてもデータが消えないのかどうかを確認してみました。適当な key に適当な value をセットし、一度 TokyoTyrant のサーバを落とします。その後、サーバを再度立ち上げて key にアクセスすると、、無事 value にアクセスすることが出来ました!スバラシイ。

最後にベンチマークを取ってみました。やっぱり読み書き速度は重要ですからね。

require 'rubygems'
require 'memcache'
require 'benchmark'

memcache = MemCache::new 'localhost:11211'
tokyo    = MemCache::new 'localhost:1978'

def random
  list = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
  return Array.new(16) do
    list[rand(list.size)]
  end.join
end

array = []
10_000.times do 
  array << random
end
# array: # ["7JN1r0Ozgw0f1G2q", "SAZxr0OzsRdf15yO", ...]

Benchmark.bm(20) do |b|
  b.report 'memcached-write' do
    array.each do |ary|
      memcache.set ary, 1, 120
    end
  end

  b.report 'tokyo-write' do
    array.each do |ary| 
      tokyo.set ary, 1
    end
  end

  b.report 'memcached-read' do
    array.each do |ary| 
      memcache.get ary
    end
  end

  b.report 'tokyo-read' do
    array.each do |ary| 
      tokyo.get ary
    end
  end
end

その結果はこちら。

                         user    system     total       real
memcached-write      0.050000  0.300000  0.350000 ( 0.883403)
tokyo-write          0.040000  0.610000  0.650000 ( 0.972349)
memcached-read       0.050000  0.440000  0.490000 ( 0.889803)
tokyo-read           0.130000  0.460000  0.590000 ( 1.000752)

memcached と比べてもほとんど遅くありませんね。これなら様々な場面で利用することが出来そうですね。期待><

また、今回は『ハッシュデータベース』しか試していませんが、『 B+-tree データベース』や『テーブルデータベース』を使えば、RDBMS のようにデータを扱うことが可能です。1 つの key に複数の value を紐付けたり、データを並べ替えたりといったこともできるようになるので、色々と応用が利きそう。(*´Д`)

ただ、ちょっと扱いづらい(わかりにくい?)のが欠点かと。。そんなときには、TokyoTyrant を ActiveRecord のように扱えるという Miyazaki Resistance が便利そうです。やっぱり慣れた形で扱えるというのは助かります。あと名前が秀逸w 東京をどげんかせんといかん。

というわけで、TokyoCabinet/TokyoTyrant のまとめ

・読み書き速度は十分に早い
・データの永続性がある(サーバがダウンしてもデータは残っている)
・memcached 互換のプロトコルがあるので、memcached とほぼ同じように扱える
・RDBMS のように柔軟に扱うことも可能
・Miyazaki Resistance は要チェック
このエントリーをはてなブックマークに追加