TokyoCabinet/TokyoTyrant を Rails で使う

インストール

TokyoCabinet
% wget http://tokyocabinet.sourceforge.net/tokyocabinet-1.3.27.tar.gz
% tar zxvf tokyocabinet-1.3.27.tar.gz
% cd tokyocabinet-1.3.27
% ./configure --prefix=/usr/local
% make
% make check
% sudo make install
TokyoCabinet Ruby API
% wget http://tokyocabinet.sourceforge.net/rubypkg/tokyocabinet-ruby-1.18.tar.gz
% tar zxvf tokyocabinet-ruby-1.18.tar.gz
% cd tokyocabinet-ruby-1.18
% ruby extconf.rb
% make
% sudo make install
TokyoTyrant
% wget http://tokyocabinet.sourceforge.net/tyrantpkg/tokyotyrant-1.1.11.tar.gz
% tar zxvf tokyotyrant-1.1.11.tar.gz
% cd tokyotyrant-1.1.11
% ./configure --prefix=/usr/local
% make
% sudo make install
TokyoTyrant Ruby API
% wget http://tokyocabinet.sourceforge.net/tyrantpkg/tokyotyrant-ruby-1.2.tar.gz
% tar zxvf tokyotyrant-ruby-1.2.tar.gz
% cd tokyotyrant-ruby-1.2
% sudo ruby install.rb

動作確認

TokyoCabinetの確認

% ruby example.rb
hop
foo:hop
bar:step
baz:jump
quux:touchdown
touchdown
foo:hop
bar:step
baz:jump
quux:touchdown
TokyoTyrantの確認

% sudo ttservctl start
% ruby example-tyrant.rb
hop
foo:hop
bar:step
baz:jump
touchdown
foo:hop
bar:step
baz:jump
quux:touchdown

ひとまず動くことを確認.

設定

特に設定ファイルは無くて,ttservctl(/usr/local/sbin/ttservctl)に直書きされている.

  8 # configuration variables
  9 prog="ttservctl"
 10 cmd="ttserver"
 11 basedir="/var/ttserver"
 12 port="1978"
 13 pidfile="$basedir/pid"
 14 logfile="$basedir/log"
 15 ulogdir="$basedir/ulog"
 16 ulimsiz="256m"
 17 sid=1
 18 dbname="$basedir/casket.tch#bnum=1000000"
 19 maxcon="65536"
 20 retval=0

サーバの実行自体は次のような感じ.

 39     $cmd \
 40       -port "$port" \
 41       -dmn \
 42       -pid "$pidfile" \
 43       -log "$logfile" \
 44       -ulog "$ulogdir" \
 45       -ulim "$ulimsiz" \
 46       -sid "$sid" \
 47       "$dbname"

ということで,これを見習って手動でやってみる.

% ttserver -port 1978 -dmn -pid "$PWD/ttserver.pid" -log "$PWD/ttserver.log" -ulog "$PWD/ttserver.ulog" -ulim "256m" -sid "1" "$PWD/casket.tch#bnum=1000000"
% ruby example-tyrant.rb
hop
foo:hop
bar:step
baz:jump
touchdown
foo:hop
bar:step
baz:jump
quux:touchdown

ここで pid/log/ulog/dbname に関しては full-path でなければ動作しないので注意が必要.

Ruby のオブジェクトを保存するには

Marshal.dump/Marshal.load を使います.

ここではちゃんと取り出せているかどうかを調べてるんですが,同一オブジェクトかどうかを判断するために == を再定義しています.

Rails で使う

試しに以下のようなサンプルを作って動かしてみます.

% rails tt-test
% cd tt-test
% ruby script/generate model User name:string
% ruby script/generate model --skip-migration UserAccessLog

ユーザ(User)とそのアクセス日時記録(UserAccessLog)です.TyokyoTyrant は memcached 互換なんですが,それはおいといて,単なるデータベースとして扱ってみます.

% ruby script/console
>> u = User.new({:name => "hogehoge"})
=> #<User id: 1, name: "hogehoge", created_at: "2009-01-09 04:11:26", updated_at: "2009-01-09 04:11:26">
>> u.access_time
=> nil
>> u.access_time = Time.now
=> Fri Jan 09 13:31:25 0900 2009
>> u.access_time
=> Fri Jan 09 13:31:25 0900 2009
>> exit
% ruby script/console
>> u = User.find(1)
=> #<User id: 1, name: "hogehoge", created_at: "2009-01-09 04:11:26", updated_at: "2009-01-09 04:11:26">
>> u.access_time
=> Fri Jan 09 13:31:25 0900 2009

これで透過的に TokyoTyrant を扱うことができました.mixiのように,アクセス時間の記録などには,非常に強力なデータベースとして扱うことができるので,使い方次第では負荷分散できそうです.