2012年11月9日金曜日

redisってなんじゃ?


redisはCで書かれたインメモリKVSでで、データセットすべてをメモリ内にもつため動作は爆速です。

また、指定回数更新が発生すると、データのスナップショットをディスクに書き込むため、プロセスが落ちてもデータを保持することができ永続化も可能です。

今回はredisをちょっと触ってみたいと思います。
さっそくインストールしてみます。
$ cd /usr/local/src
$ wget http://redis.googlecode.com/files/redis-2.6.3.tar.gz
$ tar xzf redis-2.6.3.tar.gz
$ cd redis-2.6.3
# make
# make install

インストールはこれで完了です。/usr/local/binにredisのコマンド群がインストールされました。

続いてredisを起動してみます。
# redis-server
[3042] 08 Nov 16:32:25.609 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
[3042] 08 Nov 16:32:25.609 # Unable to set the max number of files limit to 10032 (Operation not permitted), setting the max clients configuration to 992.
[3042] 08 Nov 16:32:25.610 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.
                _._                                              
           _.-``__ ''-._                                          
      _.-``    `.  `_.  ''-._           Redis 2.6.3 (00000000/0) 32 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                
 (    '      ,       .-`  | `,    )     Running in stand alone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 3042
  `-._    `-._  `-./  _.-'    _.-'                                
 |`-._`-._    `-.__.-'    _.-'_.-'|                              
 |    `-._`-._        _.-'_.-'    |           http://redis.io    
  `-._    `-._`-.__.-'_.-'    _.-'                                
 |`-._`-._    `-.__.-'    _.-'_.-'|                              
 |    `-._`-._        _.-'_.-'    |                              
  `-._    `-._`-.__.-'_.-'    _.-'                                
      `-._    `-.__.-'    _.-'                                    
          `-._        _.-'                                        
              `-.__.-'                                            

[3042] 08 Nov 16:32:25.610 # Server started, Redis version 2.6.3
[3042] 08 Nov 16:32:25.610 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[3042] 08 Nov 16:32:25.610 * The server is now ready to accept connections on port 6379

このようなコンソールログが出力され、起動されたことを示します。
リッスンポートは6379がデフォルトのようです。


また、ログの内容をみると、confファイルを指定して起動する方法も記載されているので、その様にしてみます。
まずCtrl+Cでサーバーをストップします。
そして、/etc/redis/ディレクトリを作成し、解凍したredis-2.6.3にあるredis.confを、その下に配置します。
また、データファイルの置き場として/var/lib/redisを作成しておきます。
# mkdir /etc/redis /var/lib/redis
$ cd /usr/local/src/redis-2.6.3/
$ cp redis.conf /etc/redis/

そして設定ファイルの場所を指定して再起動します。
# redis-server /etc/redis/redis.conf


ここで、同じサーバーの別のコンソールからこのサーバーへクライアント接続してみます。
$ /usr/local/src/redis-2.6.3/src
$ redis-cli
redis 127.0.0.1:6379>


このようにredisのクライアントが立上がり、コマンドを待ち受けます。

値の保持と取得はset,getで行うようです。
redis 127.0.0.1:6379> set greeting "Hello World!"
OK
redis 127.0.0.1:6379> get greeting
"Hello World!"
問題なくセットされているようです。


次に、redisサーバーを落としてみます。
[3042] 08 Nov 16:32:25.610 * The server is now ready to accept connections on port 6379
^C


再起動します。
# redis-server /etc/redis/redis.conf
redis 127.0.0.1:6379> get greeting
(nil)

永続化されていないようです。
redisはディスクに書き込む条件を設定でき、さきほどの設定ファイルをみると
save 900 1
save 300 10
save 60 10000
となっています。

ドキュメントの日本語訳をみると
このような設定がされると、次のようなタイミングで保存します:
もし最低1回、キーの変更が発生すると、900秒(15分)後
もし最低10回、キーの変更が発生すると、300秒(5分)後
もし最低10,000回、キーの変更が発生すると、60秒後

となっています。
ここではわかりやすいように、変更があったら1秒後に保存してみます。
また、ログファイル出力やデータファイルの場所も指定しておきます。
# vim /etc/redis/redis.conf
---
~略~
#logfile stdout
logfile /var/log/redis.log
~略~
save 1 1
#save 900 1
#save 300 10
#save 60 10000
~略~
---


そして再起動します。
^C
# redis-server /etc/redis/redis.conf


再びコンソールで値をセットします。
redis 127.0.0.1:6379> set greeting "Hello Word!"
OK
redis 127.0.0.1:6379> get greeting
"Hello World!"


そして、サーバーを一度落としてから再度起動してみます。
^C
# redis-server /etc/redis/redis.conf


再度コンソールで値を取得すると、、、
redis 127.0.0.1:6379> get greeting
"Hello World!"

今度は取得することができました。
データがメモリからディスクに保存されていたことがわかります。
また、起動してしまえばデータはメモリ上に再配置されているので、パフォーマンスが落ちることはありません。

ここまででも良いのですが、redisには起動スクリプトがありません。
起動スクリプトをつくって起動してみます。
あらかじめredis-serverは落としておきます。
まず、redisをデーモン化できるように設定します。
# vim /etc/redis/redis.conf
---
~略~
#daemonize no
daemonize yes
~略~
---


スクリプトファイルをgist公開している人がいたので、流用させていただきました。
ただし、redisの場所は/usr/local/sbinではなく/usr/local/binなのでその部分は変更しています。
#vim /etc/init.d/redis-server
---

#!/bin/sh
#
# redis - this script starts and stops the redis-server daemon
#
# chkconfig: - 85 15
# description: Redis is a persistent key-value database
# processname: redis-server
# config: /etc/redis/redis.conf
# config: /etc/sysconfig/redis
# pidfile: /var/run/redis.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

redis="/usr/local/bin/redis-server"
prog=$(basename $redis)

REDIS_CONF_FILE="/etc/redis/redis.conf"

[ -f /etc/sysconfig/redis ] && . /etc/sysconfig/redis

lockfile=/var/lock/subsys/redis

start() {
    [ -x $redis ] || exit 5
    [ -f $REDIS_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $redis $REDIS_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    echo -n $"Reloading $prog: "
    killproc $redis -HUP
    RETVAL=$?
    echo
}

force_reload() {
    restart
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
---


続いて、自動起動設定します。
# chkconfig --add redis-server
# chkconfig redis-server on
# /etc/init.d/redis-server start
redis-server を起動中:                                     [  OK  ]
# ps -ax | grep redis
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ
 5494 ?        Ssl    0:00 /usr/local/bin/redis-server /etc/redis/redis.conf
 5499 pts/2    S+     0:00 grep redis


うまく起動しているようです。
ここで別コンソールのredis-cliを起動してみます。
$ redis-cli
redis 127.0.0.1:6379> get greeting
"Hello World!"

成功しました。
これで起動時にredisを立ち上げることができました。

次回はこのredisをアプリケーションから使ってみたいと思います。
以上です。