2010/10/25

redisのサービスへの投入



こんにちわ、ミツバチワークス stoneです。

今回は、前回、ベンチマークをとったredisをサービスに投入した、その方法について、ご紹介します。

1 redisのセットアップ


1.1 redisをインストール

redisは、2.0.2を使用しました。
redisのインストールは、
# tar zxvf redis-2.0.2.tar.gz
# cd redis-2.0.2
# make install
ですんなり出来ました。
コンパイルされたバイナリは、/usr/local/bin/以下にコピーされています。

1.2 コンフィグ

DECOLOGでは、ApacheとMySQLを除いて、daemontoolsを利用して運用しています。
そのため、redisのコンフィグは、デフォルトのredis.confから、以下の項目を修正してあります。
(デフォルトのredis.confは、redis-2.0.2ディレクトリにあります。)
daemonize no
loglevel notice
dir /var/lib/redis/
maxmemory 8gb
これを、/etc/redis.confに保存しておきます。

1.3 ユーザーとディレクトリを設定

redis用のアカウント/グループとディレクトリを設定しておきます。
# groupadd redis
# useradd -g redis -d /var/lib/redis -s /sbin/nologin redis
アカウントとグループは、設定する必要はないのですが、なんか習慣的に作ってます。

# chmod 755 /var/lib/redis
# find /var/lib/redis/ -type f -exec rm {} \;
(useraddで作られるファイルを削除)

# mkdir -p /var/log/redis
# chmod 1777 /var/log/redis
(ログ用ディレクトリ)

1.4 daemontools用の設定

DECOLOGのサーバーでは、daemontoolsでプロセス管理する場合、/serviceに直接ディレクトリやファイルを作成しません。
/etc/superviseというディレクトリを用意して、その下にディレクトリ/ファイルの実体を作成します。
今回の場合なら、
/etc/supervise/redis/run
/etc/supervise/redis/log/run
です。
これらの確認が終わった後、
# ln -s /etc/supervise/redis /service/redis
として、daemontoolsのプロセス管理に制御を任せます。
以下では、話を簡単にするため、/serviceでのパス表記にしておきます。

file: /service/redis/run
#! /bin/sh
exec /usr/local/bin/redis-server /etc/redis.conf

file: /service/redis/log/run
#! /bin/sh
exec /usr/local/bin/setuidgid redis /usr/local/bin/multilog n20 s16777215 /var/log/redis
redisのログにもタイムスタンプが記述されるため、multilogのオプション"t"はつけませんでした。

2. redisの起動/シャットダウン


2.1 起動

daemontoolsが動いているので、/service/redis/runが作成された時点で、redisは起動されます。
手動オペレーションで、redisを落とした場合は、
# svc -u /service/redis
で、redisが起動されます。

2.2 シャットダウン

該当するドキュメントを見つけられなくて、結局、ソースコードを追っかけてわかったのですが、redisは、TERMシグナルを受け取ると、データのsnapshotを保存した後にプロセスを終了します。
なので、
# svc -t /service/redis
で、キレイにシャットダウンすることが出来ます。

2.3 再起動

単純に、
# svc -tu /service/redis
で、再起動をかけます。

再起動にかかる時間は、ほぼsnapshotを保存する時間です。
なので、事前にログを見て、所要時間を予測することが可能です。
いままでの実績で言うと、30Mbytes程度なら1秒以下、1〜2GBytesでは30秒程度かかります。

3. 監視項目


サービスに投入する前に、状態監視できるようにしておきます。
※DECOLOGでは監視にZABBIXを使っています→http://tech.dclog.jp/2010/09/decolog.html

数年前にZABBIXを導入してから、状態が監視できない状態で何かオペレーションするというのが、ものすごく怖く感じるようになりました。
なにか、目隠し状態で作業しているような感覚です。
何か新要素を投入を決めるときは、「稼働状態を取得できる」というのも大事な要素になります。

3.1 状態の取得

redisには、redis-cliという便利なクライアントツールが用意されています。
これを利用して、稼働中のredisの状態を監視します。

redisには、infoというコマンドが用意されていて、redis-serverの状態を出力してくれます。
$ /usr/local/bin/redis-cli info
redis_version:2.0.2
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
process_id:27077
uptime_in_seconds:786661
uptime_in_days:9
connected_clients:1
connected_slaves:0
blocked_clients:0
used_memory:34944584
used_memory_human:33.33M
changes_since_last_save:4903
bgsave_in_progress:0
last_save_time:1287647443
bgrewriteaof_in_progress:0
total_connections_received:12550855
total_commands_processed:37684666
expired_keys:6830
hash_max_zipmap_entries:64
hash_max_zipmap_value:512
pubsub_channels:0
pubsub_patterns:0
vm_enabled:0
role:master
db1:keys=59136,expires=59136

1分ごとにredisにinfoコマンドを発行して、状態を取得します。
file: /etc/cron.d/redisstat
* * * * * root /usr/local/bin/redis-cli info > /var/log/redisstat.log.new; mv /var/log/redisstat.log.new /var/log/redisstat.log
一度、redisstat.log.newに出力してから、redisstat.logにmvしているのは、
「redis-cli info」がredisサーバーからの応答を待ってる間に、ZABBIXが値を取りにきて、おかしな値が出力されるケースがある為です。
今のところ、redisでは、そういうケースはありませんが、ApacheやMySQLでは、そういう、いわば「滞空時間」にZABBIXが値を取得しにくるケースに遭遇したことがあります。


3.2 ZABBIXに項目を追加

infoから出力されるデータのうち、used_memoryとconnected_clientsを監視することにしました。
zabbixへの項目追加は、以下のようになります。
UserParameter=redis.connections,grep connected_clients /var/log/redisstat.log | cut -d':' -f2
UserParameter=redis.used_memory,grep 'used_memory:' /var/log/redisstat.log | cut -d':' -f2

これ、より汎用的に
UserParameter=redis.stat[*],grep $1: /var/log/redisstat.log | cut -d':' -f2
でも、いいかもしれませんね。
今、思いつきました(笑)

3.3 スクリーンを作成

ZABBIX上で、上記の2項目の他に、
・ロードアベレージ
・ネットワークのin/out
をまとめて、スクリーンを作って、監視体制の整備は、完成です。



新しい要素を加える場合、だいたい上記のような流れで、監視体制までを準備してから、サービスへ投入しています。
今回、redisをサービスに投入した後に出くわしたトラブルについても書こうと考えていたのですが、サービス投入までの記述が思った以上の分量だったので、トラブルについては、次回以降にしたいと思います。

では、また次回に♪