Redis + Sentinel で自動フェイルオーバ in Amazon VPC を試してみた

お久しぶりです。
最後にブログを更新したのがInternal ELBが登場して勢いで書いた6月11日。。。更新してなさすぎですね。

そこで今回試してみたのは、Redis + Sentinelの自動フェイルオーバをAWS VPC環境で実現するというものです。

元々は「 RedisをKeepalivedでフェイルオーバーする構成案 - 酒日記 はてな支店 」を参考にして構築しようと考えていたのですが、VPC(というかAWS)の環境ではbroadcastやmulticastが使用できないので、VRRPが使えず断念。そこで少し途方にくれつつ考えたのが、Sentinelを使う方法。

Redisについては特に説明は必要ないと思いますので、Sentinelについて簡単に。

  • 監視: masterやslaveが期待通り動いているかどうかを定期的に監視
  • 通知: 指定したログレベルのものが発生した時に、管理者やプログラムに通知を行う
  • 自動フェイルオーバ: master障害時にslaveをmasterへと昇格させる。redisを使っているアプリケーションに新しいmasterのIPアドレスを通知する

詳細はこちら( Redis Sentinel Documentation – Redis )を参照していただければと。

構成

構成としては、以下のような感じです。すべてCentOS6.3(ちょっとだけカスタムAMI)を使っています。

  • web(application)サーバ2台
  • Redis + Sentinelサーバ2台

f:id:matetsu:20121228110332p:plain
※ #ヤマン さんによる「 VPCでアベイラビリティゾーン越しにプライベートIPを共有する(Source/Descチェック外し) - c9日記 -カタヤマンがプログラマチックに今日もコードアシスト 」のような構成です。

webサーバは特に言及することはなく、Redisに接続するためのIPとしてVIPである 172.16.0.10 を使うようにするくらいです。
Redisサーバでは、以下のような設定をします。

  • 両機のループバックインターフェイスに予めIPエイリアスとして 172.16.0.10/32 を設定
  • インスタンスのSource/Dest Checkをdisableにしておく←これ重要(masterにするスクリプトでもdisableにするようにしてるけど)

VPCのroute tableの設定はmaster/slaveの設定をするときにスクリプトを使って一気にやってしまうので、先に設定しておく必要はない。

Redisの設定(初期設定)

master/slaveの関係を作る前のRedis初期設定は以下のようにしています。

slaveof no one
masterauth [pass]
requireauth [pass]

くらいしか変えていません。

Sentinelの設定はこちら。まだ特に関しの設定はせずに、起動するだけになっています。

この状態で、まずはサービスを起動します。

# service redis start
# service sentinel start

Master/Slaveの設定

続いて、redis01をmaster、redis02をslaveとして設定します。

基本的には単純にredis-cliからslaveofコマンドを実行するだけなのですが、requireauthを設定しているので、パスワードを入れるのが面倒だったので、以下の様なpythonスクリプトにしています。

また、masterノードのVIP(ループバックに設定したやつ)にwebサーバからのアクセスを向かせるために、VPCのroute tableを設定するためのスクリプトも準備しておきます。ACCESS_KEYやSECRET_ACCESS_KEY,routetable_idは自分の環境にあわせてください。

このスクリプトでは、自分自身のインスタンスIDにVIPへのアクセスをルーティングするようにしています。

このスクリプトと、実行ノードをmasterにするスクリプト(redis-to-master.sh)、指定したmasterノードのslaveにするスクリプト(redis-to-slave.sh)を組み合わせて、master/slave構成を取るようにする。


redis-to-master.shとredis-to-slave.shの中で、sentinelが監視するクラスタの情報を登録するためにsentinel.confを変更する処理も入っています。この処理は、以下のテンプレートのmasterノード情報をsedを使って置換しているだけです。

以下のように実行して少し待てば設定完了です。

[redis01]# redis-to-master.sh
[redis02]# redis-to-slave.sh redis01

フェイルオーバを試す

ここからが本題です。
フェイルオーバはSentinelが自動で行なってくれて、masterが切り替わったことをアプリケーションに伝えてくれるとのことですが、VIPを使ってVIPの向き先を変更することで対応しています。

sentinelの設定で指定している client-reconfig-script で指定しているスクリプト redis-failover.sh では failover endが渡された時に route-table を書き換えてVIPを自身のインスタンスIDに向けるようにしています。こうすることで、webサーバ側では特に接続先を変えなくてもそのままの設定で接続できます。もちろん、failover endが渡ってきているので、自動フェイルオーバが完了して、もともとslaveだったノードがmasterとして稼働します。

また、SentinelがWarning以上のステータスを検知した場合に通知するためには notification-script に通知スクリプトを指定する。

これで、フェイルオーバが起きたことを検知することもできる(もちろん監視も忘れずに)。
フェイルオーバが起きた時には、以下のようなログが出力される。上のnotification-scriptだと、5通のメールが来ることになる。。。これも「+hoge」となっているEvent Typeを見て分岐したりもできるので、もう少し改良の余地はあるかと思います。

[23304] 15 Jan 19:59:06.858 # +sdown master mymaster MASTER_IP 6379
[23304] 15 Jan 19:59:06.859 # +odown master mymaster MASTER_IP 6379 #quorum 1/1
[23304] 15 Jan 19:59:17.395 # +failover-detected master mymaster MASTER_IP 6379
[23304] 15 Jan 19:59:17.495 # +failover-end master mymaster MASTER_IP 6379
[23304] 15 Jan 19:59:17.495 # +switch-master mymaster MASTER_IP 6379 SLAVE_IP 6379

masterが切り替わったあとも、webサーバからはVIPでそのままアクセスできることも確認できた。まだまだ検証しないといけないこともあるけれど、それなりに簡単にフェイルオーバの仕組みを構築することができました。

Sentinelについては、簡単に動かしてみた程度なので、もう少し詳しく調べてみたいなと思っています。


年末に勢いで3分の2くらい書いたところで放置してしまっていましたが、このまま眠らせておくのもアレですし、とりあえずアウトプットしておこうとようやく書き上げました。不備などありましたらご指摘ください。gistも(ほぼ)初めて使って見ました。
今年はちゃんとブログにアウトプットしていきたい!