FreeBSDでKyotoTycoonを使ってみた

KyotoTycoon とは?

 KyotoTycoonはプロセス組み込み軽量データベースライブラリであるKyoto Cabinetをネットワーク越しに利用出来るようにするKVSのサーバです。同じKVSで有名なmemcachedの場合データベースを全てオンメモリで処理しているため電源を落としたりプロセスを再起動させると保存していたデータが全部初期化されてしまう特徴があります。 KyotoTycoonはファイルにデータを書き込み永続的なデータ保存ができる「memcachedのデータ永続化版」の特徴を持っています。

 またサーバの起動オプションでmemcachedと同じようにオンメモリに高速にデータストアーできるように設定することも可能な特徴も合わせ持っているようです。また付属するプラグインを利用する事によりmemcachedのプロトコルを解釈する事ができるためプログラムシステムを全く変更することなくmemcachedと置き換えることも可能です。データベースのホットバックアップやレプリケーションも出来るため耐障害性能のあるKVSとして利用価値があります。

KyotoCabinet をインストール

FreeBSDには便利なportsシステムがあり簡単にアプリケーションのインストールができるのですがKyotoCabinetのportsが古いためtarballからinstallします。

http://fallabs.com/kyotocabinet/

$ wget http://fallabs.com/kyotocabinet/pkg/kyotocabinet-1.2.58.tar.gz
$ export CPPFLAGS="-march=i686"
$ ./configure
$ gmake
$ su
# make install

lua のインストール

portsから

$ sudo portinstall lang/lua

KyotoTycoonをmakeする際にライブラリが見つけられないのでシンボリックリンクを作成

$ ln -s /usr/local/include/lua51 /usr/local/include/lua
$ ln -s /usr/local/lib/liblua-5.1.so /usr/local/lib/liblua.so

KyotoTycoon のインストール

portsに存在しませんのでtarballからinstallします。 http://fallabs.com/kyototycoon/

$ wget http://fallabs.com/kyototycoon/pkg/kyototycoon-0.9.42.tar.gz
$ ./configure --enable-lua
$gmake
$su
#make install

KyotoTycoon の起動

$ktserver
2011-06-05T02:28:48.710949+09:00: [SYSTEM]: ================ [START]: pid=64582
2011-06-05T02:28:48.712529+09:00: [SYSTEM]: opening a database: path=:
2011-06-05T02:28:48.713851+09:00: [SYSTEM]: starting the server: expr=:1978
2011-06-05T02:28:48.714925+09:00: [SYSTEM]: server socket opened: expr=:1978 timeout=30.0
2011-06-05T02:28:48.715320+09:00: [SYSTEM]: listening server socket started: fd=3

オプションを何も指定しないで起動させるとオンメモリなKVSとして動作します。 起動させた状態で別コンソールなどからKVSを操作してみます。

$ktremotemgr set key1 hoge
$ktremotemgr get key1
hoge
$ktremotemgr set key2 moe
$ktremotemgr get key2
moe

#expire 5sec
$ktremotemgr set -xt 5 foo bar1

サーバをstopするには[ctl-C]

ktserverオプション一覧

-host str : specifies the host name of the server.
-port num : specifies the port number of the server.
-tout num : specifies the timeout in seconds.
-th num : specifies the number of worker threads. By default, it is 8.
-log file : specifies the path of the log file. By default, logs are written into the standard output.
-li : sets the logging level "INFO".
-ls : sets the logging level "SYSTEM".
-le : sets the logging level "ERROR".
-lz : sets the logging level "NONE".
-ulog dir : specifies the path of the update log directory. By default, it is disabled.
-ulim num : specifies the limit size of each update log file.
-uasi num : specifies the interval of synchronization of update log files. By default, it is disabled.
-sid num : specifies the server ID number.
-ord : opens the database as a reader.
-oat : opens the database with the auto transaction option.
-oas : opens the database with the auto synchronization option.
-onl : opens the database with the no locking option.
-otl : opens the database with the try locking option.
-onr : opens the database with the no auto repair option.
-asi num : specifies the interval of auto synchronization. By default, it is disabled.
-ash : does physical synchronization while auto synchronization.
-bgs dir : specifies the path of the background snapshot directory. By default, it is disabled.
-bgsi num : specifies the interval of background snapshotting. By default, it is 180.
-bgsc str : specifies the compression algorithm of the snapshot. "zlib", "lzo", are "lzma" are supported.
-dmn : switches to a daemon process.
-pid file : specifies the file to contain the process ID to send signals by.
-cmd dir : specifies the command search path for outer commands. By default, it is the current directroy.
-scr file : specifies the script file for the scripting extention.
-mhost str : specifies the host name of the master server of replication.
-mport num : specifies the port number of the master server of replication.
-rts file : specifies the file to contain the replication time stamp.
-riv num : specifies the interval of each replication operation in milliseconds. By default, it is 0.04.
-plsv file : specifies the shared library file of a pluggable server.
-plex str : specifies the configuration expression of a pluggable server.
-pldb file : specifies the shared library file of a pluggable database.

DBの命名規則

内部で利用しているKyotoCabinetのDBの種類がいくつかありDBファイルの拡張子等で指定する事が可能です。

  • ":" :スタッシュDB(デフォルト、省メモリDB)
  • "*" :オンメモリハッシュDB
  • "%" :オンメモリツリーDB
  • ".kch" :ファイルハッシュDB
  • ".kct" :ファイルツリーDB
  • ".kcd" :ディレクトリハッシュDB
  • ".kcf" :ディレクトリツリーDB

FreeBSD用KyotoTycoonスタートアップスクリプト

設定内容がハードコートしてあります。適宜自分の設定に書き換えてお使い下さい。現在の設定はmemcachedプラグインを利用してファイルハッシュDBを64MBのメモリマップで使う設定になっております。 スタートアップスクリプト ktservctl

設置場所は /usr/local/etc/rc.d/ktservctl

起動: /usr/local/etc/rc.d/ktservctl start

停止: /usr/local/etc/rc.d/ktservctl stop

再起動: /usr/local/etc/rc.d/ktservctl restart

#!/bin/sh

#----------------------------------------------------------------
# Startup script for the server of KyotoTycoon
#----------------------------------------------------------------

# configuration variables
prog="ktservctl"
cmd="ktserver"
basedir="/var/ktserver"
port="1978"
pidfile="$basedir/pid"
logfile="$basedir/log"
#ulogdir="$basedir/ulog"
#ulimsiz="256m"
#sid=1
#mhost="remotehost1"
#mport="1978"
#rtsfile="$basedir/rts"
dbname="$basedir/casket.kch#opts=l#bnum=100000#msiz=64m#dfunit=8"
timeout=10
plsv="/usr/local/libexec/ktplugservmemc.so"
plex="opts=f"
retval=0


# setting environment variables
LANG=C
LC_ALL=C
PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
export LANG LC_ALL PATH


# start the server
start(){
  printf 'Starting the server of Tokyo Tyrant\n'
  mkdir -p "$basedir"
  if [ -z "$basedir" ] || [ -z "$port" ] || [ -z "$pidfile" ] || [ -z "$dbname" ] ; then
    printf 'Invalid configuration\n'
    retval=1
  elif ! [ -d "$basedir" ] ; then
    printf 'No such directory: %s\n' "$basedir"
    retval=1
  elif [ -f "$pidfile" ] ; then
    pid=`cat "$pidfile"`
    printf 'Existing process: %d\n' "$pid"
    retval=1
  else
    cmd="$cmd -port $port -le -dmn -pid $pidfile"

    if [ -n "$timeout" ] ; then
      cmd="$cmd -tout $timeout"
    fi
    if [ -n "$plsv" ] ; then
      cmd="$cmd -plsv $plsv"
    fi
    if [ -n "$plex" ] ; then
      cmd="$cmd -plex $plex"
    fi

    if [ -n "$logfile" ] ; then
      cmd="$cmd -log $logfile"
    fi
    if [ -n "$ulogdir" ] ; then
      mkdir -p "$ulogdir"
      cmd="$cmd -ulog $ulogdir"
    fi
    if [ -n "$ulimsiz" ] ; then
      cmd="$cmd -ulim $ulimsiz"
    fi
    if [ -n "$sid" ] ; then
      cmd="$cmd -sid $sid"
    fi
    if [ -n "$mhost" ] ; then
      cmd="$cmd -mhost $mhost"
    fi
    if [ -n "$mport" ] ; then
      cmd="$cmd -mport $mport"
    fi
    if [ -n "$rtsfile" ] ; then
      cmd="$cmd -rts $rtsfile"
    fi

    printf "Executing: %s\n" "$cmd"
    cmd="$cmd $dbname"
    $cmd
    if [ "$?" -eq 0 ] ; then
      printf 'Done\n'
    else
      printf 'The server could not started\n'
      retval=1
    fi
  fi
}


# stop the server
stop(){
  printf 'Stopping the server of Tokyo Tyrant\n'
  if [ -f "$pidfile" ] ; then
    pid=`cat "$pidfile"`
    printf "Sending the terminal signal to the process: %s\n" "$pid"
    kill -TERM "$pid"
    c=0
    while true ; do
      sleep 0.1
      if [ -f "$pidfile" ] ; then
        c=`expr $c + 1`
        if [ "$c" -ge 100 ] ; then
          printf 'Hanging process: %d\n' "$pid"
          retval=1
          break
        fi
      else
        printf 'Done\n'
        break
      fi
    done
  else
    printf 'No process found\n'
    retval=1
  fi
}


# send HUP to the server for log rotation
hup(){
  printf 'Sending HUP signal to the server of Tokyo Tyrant\n'
  if [ -f "$pidfile" ] ; then
    pid=`cat "$pidfile"`
    printf "Sending the hangup signal to the process: %s\n" "$pid"
    kill -HUP "$pid"
    printf 'Done\n'
  else
    printf 'No process found\n'
    retval=1
  fi
}


# check permission
if [ -d "$basedir" ] && ! touch "$basedir/$$" >/dev/null 2>&1
then
  printf 'Permission denied\n'
  exit 1
fi
rm -f "$basedir/$$"


# dispatch the command
case "$1" in
start)
  start
  ;;
stop)
  stop
  ;;
restart)
  stop
  start
  ;;
hup)
  hup
  ;;
*)
  printf 'Usage: %s {start|stop|restart|hup}\n' "$prog"
  exit 1
  ;;
esac

# exit
exit "$retval"

# END OF FILE

memcachedクライアントから操作するには

ktserver 起動時にktplugservmemc.soプラグインを指定することでmemcachedプロトコルを扱えるようになります。 起動オプション例

$ ktserver -plsv /usr/local/libexec/ktplugservmemc.so -plex 'opts=f' 'casket.kch#opts=l#bnum=100000#msiz=64m#dfunit=8'

memcachedクライアント

Masahiro Naganoさん謹製の perlモジュール Cache::Memcached::IronPlate からアクセスしてみます。

Cache::Memcached::IronPlate は Cache::Memcached::Fast のオブジェクトを渡して使うperlモジュールで memcached injectionを防ぐための機能が備わったmemcachedクライアントライブラリです。

iron.pl

#!/usr/bin/env perl
use strict;
use warnings;
use Cache::Memcached::IronPlate;
use Cache::Memcached::Fast;
use Data::MessagePack;
use Data::Dumper;
use utf8;


my $memd = Cache::Memcached::IronPlate->new(
    cache => Cache::Memcached::Fast->new({      
        servers => [ { address => 'localhost:11211' }],
        serialize_methods => 
            [ 
                sub { Data::MessagePack->pack(+shift)}, 
                sub { Data::MessagePack->unpack(+shift)} 
            ]
      })
);

$memd->set(key1 => +{ foo => 1, bar => 1});

warn Dumper $memd->get("key1");


$memd->set(key2 => +{foo => "日本語"});

warn Dumper $memd->get("key2");


$memd->set("key 3 キー\n" => "bar");
warn Dumper $memd->get("key 3 キー\n");

実行結果

$perl iron.pl
$VAR1 = {
          'bar' => 1,
          'foo' => 1
        };
$VAR1 = {
          'foo' => '日本語'
        };
$VAR1 = 'bar';

参考)

[http://www.slideshare.net/estraier/kyoto-tycoon-guide-in-japanese](http://www.slideshare.net/estraier/kyoto-tycoon-guide-in-japanese)

追記2011-06-17

FreeBSD用の自動起動用のスクリプト

rc.conf追加

ktserver_enable="YES"
ktserver_args="-port 1978 -le -dmn -pid /var/ktserver/pid -tout 10 -plsv /usr/local/libexec/ktplugservmemc.so -plex opts=f -log /var/ktserver/log /var/ktserver/casket.kch#opts=l#bnum=100000#msiz=64m#dfunit=8"

自動起動スクリプト

#!/bin/sh
#
# $FreeBSD: ports/databases/kyototycoon/files/ktserver,v 1.3 2011/06/17 00:12:51 dougb Exp $
#
#
# PROVIDE: ktserver
# REQUIRE: DAEMON
# KEYWORD: shutdown

. /etc/rc.subr

name="ktserver"
rcvar=`set_rcvar`

load_rc_config $name
: ${ktserver_enable:="NO"}
: ${ktserver_args=""}

command="/usr/local/bin/${name}"
command_args="${ktserver_args}"

run_rc_command "$1"
created:

Back to top