master slave 構成を取っている Redis で、master が落ちた場合に slave を昇格させてフェイルオーバーしたいという要件がありまして、Keepalived と組み合わせて構成してみました。Redis の運用経験がないのでご意見などいただければありがたいです。
- Scientific Linux 6.2
- keepalived-1.2.2-3
- redis-2.4.10
前提
- Redis のレプリケーションではマルチマスター構成を取ることができない
- Redis の slave は起動時に master に接続し、全データを取得してコピーを取る
- その後は順次 master で更新されたデータをコピーする
- redis-cli で slaveof コマンドを実行することで、動的に master, slave を切り替えることが可能
このような作りになっているため、2ホスト間で VIP を持たせ、アプリケーションからは常に VIP に接続。VIP を持っているホストが Redis の master になり、もう片方が slave、という状態を作ります。
- VIP を持っている master (のホスト、ネットワークなど) が落ちた場合
- slave の Keepalived が VIP をフェイルオーバーして引き継ぐ
- slave redis-server を master 状態に変更する
- master の redis-server プロセスが落ちた場合
- master でプロセスの停止を検知し、Keepalived を停止して強制的にフェイルオーバーさせる
Keepalived の設定
keepalived.conf で VIP の設定と、redis-server に対する死活監視の設定を行います。
vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 11 priority 100 advert_int 1 notify_master /usr/local/sbin/redis-to-master.sh notify_backup /usr/local/sbin/redis-to-slave.sh authentication { auth_type PASS auth_pass xxxx } virtual_ipaddress { 192.168.1.10 } } virtual_server 127.0.0.1 16379 { delay_loop 5 lb_algo rr real_server 127.0.0.1 6379 { MISC_CHECK { misc_path "/usr/local/sbin/redis-check.sh" misc_timeout 30 } } }
notify_master, notify_backup で VIP の状態が変わった際に、Redis に対して master, slave に移行する指示を発行するスクリプトを指定しています。ついでに redis.conf も書き換えてしまいます。
#!/bin/sh # redis-to-master.sh redis-cli slaveof no one perl -pi -e 's/^slaveof.*/slaveof no one/' /etc/redis.conf
#!/bin/sh # redis-to-slave.sh PEER_HOST="192.168.1.11" # 相手のホスト PEER_PORT=6379 redis-cli slaveof $PEER_HOST $PEER_PORT perl -pi -e "s/^slaveof.*/slaveof $PEER_HOST $PEER_PORT/" /etc/redis.conf
virtual_server 127.0.0.1 16379 の設定はダミーで、MISC_CHECK で Redis の死活監視を行うスクリプトを定期的に実行するためのものです。
#!/bin/sh # redis-check.sh for TRIES in `seq 1 3` do RESULT=`redis-cli ping` if [ "${RESULT}" = "PONG" ]; then exit 0 fi echo "ping failed ${TRIES}" | logger -t redis-check sleep 1 done echo "redis server was down. shutdown keepalived." | logger -t redis-check service keepalived stop exit 1
PING を発行し、PONG が返ってくれば正常終了。3回試行して成功しなければ keepalived stop することで強制的にフェイルオーバーを行います。
動作
master になっているホストが突然死した場合
KVM の仮想マシン host1 を virsh destroy で落とした時の、host2 側のログです。
==> /var/log/messages <== Aug 2 12:30:15 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Transition to MASTER STATE Aug 2 12:30:16 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Entering MASTER STATE Aug 2 12:30:16 host2 Keepalived_vrrp: VRRP_Instance(VI_1) setting protocol VIPs. Aug 2 12:30:16 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.1.10 Aug 2 12:30:16 host2 Keepalived_healthcheckers: Netlink reflector reports IP 192.168.1.10 added ==> /var/log/redis/redis.log <== [2332] 02 Aug 12:30:16 * MASTER MODE enabled (user request)
バックアップホストで動作している Keepalived が MASTER に切り替わり、そのタイミングで Redis も master 状態に移行します。
master の redis-server が死んだ場合
host1 で pkill -KILL redis-server した場合のログです。
==> /var/log/messages <== Aug 2 12:39:30 host1 redis-check: ping failed 1 Aug 2 12:39:31 host1 redis-check: ping failed 2 Aug 2 12:39:32 host1 redis-check: ping failed 3 Aug 2 12:39:33 host1 redis-check: redis server was down. shutdown keepalived. Aug 2 12:39:33 host1 Keepalived: Terminating on signal Aug 2 12:39:33 host1 Keepalived: Stopping Keepalived v1.2.2 (03/20,2012) Aug 2 12:39:33 host1 kernel: IPVS: set_ctl: invalid protocol: 0 127.0.0.1:16379 rr Aug 2 12:39:33 host1 kernel: IPVS: set_ctl: invalid protocol: 0 127.0.0.1:16379 rr Aug 2 12:39:33 host1 Keepalived_healthcheckers: Terminating Healthchecker child process on signal Aug 2 12:39:33 host1 Keepalived_vrrp: Terminating VRRP child process on signal Aug 2 12:39:33 host1 Keepalived_vrrp: VRRP_Instance(VI_1) removing protocol VIPs.
ヘルスチェックが3回連続で失敗し、host1 の Keepalived が停止。
==> /var/log/redis/redis.log <== [2332] 02 Aug 12:39:28 * Connecting to MASTER... [2332] 02 Aug 12:39:28 * MASTER <-> SLAVE sync started [2332] 02 Aug 12:39:28 * Non blocking connect for SYNC fired the event. [2332] 02 Aug 12:39:28 # I/O error writing to MASTER: Connection refused (略) [2332] 02 Aug 12:39:38 * Connecting to MASTER... [2332] 02 Aug 12:39:38 * MASTER <-> SLAVE sync started [2332] 02 Aug 12:39:38 * Non blocking connect for SYNC fired the event. [2332] 02 Aug 12:39:38 # I/O error writing to MASTER: Connection refused [2332] 02 Aug 12:39:39 * MASTER MODE enabled (user request) ==> /var/log/messages <== Aug 2 12:39:38 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Transition to MASTER STATE Aug 2 12:39:39 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Entering MASTER STATE Aug 2 12:39:39 host2 Keepalived_vrrp: VRRP_Instance(VI_1) setting protocol VIPs. Aug 2 12:39:39 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.1.10 Aug 2 12:39:39 host2 Keepalived_healthcheckers: Netlink reflector reports IP 192.168.1.10 added Aug 2 12:39:44 host2 Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.1.10
host2 側で Keepalived と redis が MASTER になります。
まとめ
Keepalived で MASTER になっているほうを Redis の MASTER にすることで、フェイルオーバー構成を作ることができました。
まだ実戦投入前なので、なにか見逃している問題点などあれば教えていただけると嬉しいです。