Pivotal Knowledge Base

フォローする

Redis マスターとスレーブサーバー間の自動フェールオーバーを行うための HAProxy と Redis Sentinel の設定方法

環境

製品 バージョン
Redis Sentinel  
HAProxy  

目的

HAProxy サーバーを利用した高可用性のためのマスターとスレーブ Redis レプリカインスタンス間における自動フェールオーバーは、Redis Sentinel にて容易に設定可能である。

Redis Sentinel は、ドキュメント(http://redis.io/topics/sentinel)によると、以下のタスクを実行することにより Redis インスタンスの自動フェールオーバーを監視・管理するよう設計されている。

  • 監視: Sentinel は常に、マスターとスレーブのインスタンスが想定通りに動作しているかどうかを確認する。
  • 通知: Sentinel は、管理対象 Redis に何か問題が発生した際に、API を介してシステム管理者やその他コンピュータープログラムに、通知することができる。
  • 自動フェールオーバー: マスターが想定通りに動作していない場合は、Sentinel はスレーブをマスターに昇格させるフェールオーバー処理を開始することができる。その他のスレーブは新マスターを使用するよう再設定され、Redis サーバーを使用しているアプリケーションには次回接続時の新アドレスを通知する。
  • 設定プロバイダー: Sentinel はクライアントのサービスディスカバリー情報のプロバイダーとして振る舞う。クライアントは、指定したサービスに対応する現在の Redis マスターのアドレスを問い合わせるため、Sentinel に接続する。フェールオーバーが発生した場合は、Sentinel は新しいアドレスを通知する。

Sentinel を用いて、Redis マスターの監視と、マスターダウン時にスレーブをマスターに昇格することによる自動フェールオーバーを制御することができる。

HAProxy 1.5 以降、Redis の自動フェールオーバーを実行するために、新しくビルトインの TCP ヘルスチェック機能が搭載されている。フェールオーバー発生後に、フロントエンドのクライアントに対する Redis の IP・ポートが変更されるのを防ぐために、対象 Redis インスタンスがマスターであるかスレーブであるか確認するよう HAProxy の TCP ヘルスチェック機能を設定する。この設定は、HAProxy がアクティブなマスターインスタンスへのみ接続のプロキシーを行うことを保証するために必要である。

以下の簡単なデモにおいては、Redis-3.0.1 を用い、tcServer(Tomcat 7 ベース)におけるユーザーの HTTP セッションの自動フェールオーバーを実現するため Ubuntu 14.04 ベースのホスト上で稼働する Redis サーバー上に格納し、tcServer のフロントエンドロードバランサーとして HAProxy-1.5.12 を用いる。 

Redis Sentinel と、Redis サーバー間で TCP ロードバランシングを行う HAProxy の構成図は以下である。

<クライアント>---6378---<HAProxy>---6379/6380---<Redis_6379 | Redis_6380>---<Sentinel_26379>                                                                                       

  • HAProxy - ポート 6378 番経由でのクライアントアプリケーションからの接続をバックエンドの Redis マスターサーバーへプロキシーを行うためのフロントエンド TCP ロードバランサー
  • Redis_6379 - 使用ポート番号 6379 のマスターサーバー
  • Redis_6380 - 使用ポート番号 6380 のスレーブサーバー
  • Sentinel - Sentinel はポート番号 26379 で、マスターサーバーとスレーブサーバーを監視し、マスターダウン時にスレーブをマスターロールに昇格するために稼働

Redis マスター・スレーブ、あるいは HAProxy サーバーをまだインストールしていない場合は、以下を参照のこと。

手順

Redis HA に対する HAProxy ロードバランサーの設定と配備

1) /etc/haproxy/haproxy.conf ファイルに以下のパラメーター値を設定する。設定内容を保持するためコメント行(# から始まる行)を追加することを推奨する。

# フロントエンド ft_redis で使用するための一連の TCP コネクションタイムアウト値を設定。
# connect には、サーバー接続を試み、成功と判断される最大待ち時間を設定。 
# server と client には、応答あるいはデータが送られるまでの最大待ち時間を設定。
defaults REDIS
mode tcp
timeout connect 3s
timeout server 6s
timeout client 6s

# 上記の defaults REDIS 設定とバックエンド bk_redis TCP ヘルスチェック設定を用いた 
# クライアント接続を受け入れるためのリスンソケットを指定。
frontend ft_redis
bind *:6378 name redis
default_backend bk_redis

# バックエンドの Redis プロキシーサーバーにおける TCP ヘルスチェック設定。 
# クライアントからの接続をマスターにのみフォワードすることを保証。
backend bk_redis
option tcp-check
tcp-check connect
tcp-check send PING\r\n
tcp-check expect string +PONG
tcp-check send info\ replication\r\n
tcp-check expect string role:master
tcp-check send QUIT\r\n
tcp-check expect string +OK
server redis_6379 localhost:6379 check inter 1s
server redis_6380 localhost:6380 check inter 1s 

2) HAProxy サーバーを起動する。

/etc/init.d/haproxy start

Redis マスターサーバーとスレーブサーバー間で自動フェールオーバーを行うための Redis Sentinel の設定と配備

1) 以下の内容で、/etc/redis/sentinel_26379.conf ファイルを生成する。

# Sentinel の使用ポート番号、ログファイルのパス、作業ディレクトリー、デーモンサービス稼働の設定を行う。

port 26379

daemonize yes

pidfile "/var/run/sentinel_26379.pid"

logfile "/var/log/sentinel_26379.log"

dir /var/lib/redis/sentinel_26379

# ポート番号 6379 で稼働中の redis_6379 マスターを監視し、フェールオーバーを開始するためには 
# 最低限 1 クオラムの Sentinel の合意をもって、ODOWN 状態(マスターダウン)であると判断する。 
# Sentinel は自動的にスレーブを見つけ、スレーブを追加するよう設定を書き換える。 
# したがって、スレーブを明示的に指定する必要はない。なお、スレーブがマスター状態に昇格した際にも 
# 設定ファイルが書き換えられる。

sentinel monitor master01 localhost 6379 1

# 必要に応じて、マスターやスレーブへの認証に使用するパスワードを指定する。
# Redis において認証が '必要な' インスタンスと 'そうでない' インスタンスが混在する場合は、 全てのインスタンスで 
# 同じパスワードを設定する必要がある。本デモにおける Redis サーバーはパスワード認証を必要としていない。

#sentinel auth-pass myredis mypass

# マスターやスレーブ、Sentinel がダウンし SDOWN 状態(各ノードダウン)でアクセス不能と判断するまでの待ち時間(ミリ秒)
# を指定する。

sentinel down-after-milliseconds master01 3000

# 以下のような理由で使用するフェールオーバータイムアウト(ミリ秒)を指定する。
# * 同一マスターにてフェールオーバー処理がタイムアウトし、再実行を試みる場合
# * 現在の設定で、スレーブが旧マスターにレプリケーションを行おうとしており、新マスターへ強制的に行うようにするまでの猶予時間
# * フェールオーバーがすでに実行されているが設定変更が行われない(新スレーブが SLAVE NO ONE として通知されていない) 
#   状態でフェールオーバーをキャンセルするまでのタイムアウト値
# * フェールオーバー実行中に、新マスターのスレーブとして全てのスレーブが再設定されるまでの最大の待ち時間

sentinel failover-timeout master01 6000

# フェールオーバー実行中に、新スレーブとして再設定するスレーブ数を指定する。 
# スレーブがクエリーを実行するよう使用されている場合、マスターと同期処理を実行している間、スレーブへのアクセスが不能
# となる状態を避けるために、小さい値を指定することが推奨される。

sentinel parallel-syncs master01 6379 1

2) 実行可能な Sentinel サービススクリプトを記述する。

/etc/init.d/sentinel_26379

#!/bin/bash
# Redis Sentinel の起動・停止・再起動用スクリプト

NAME=`basename ${0}`
EXEC=/usr/local/bin/redis-server
PIDFILE="/var/run/${NAME}.pid"
CONF="/etc/redis/${NAME}.conf"

PID=`cat $PIDFILE 2> /dev/null`
case "$1" in
     start)
         echo "Starting $NAME ..."
         touch $PIDFILE
         exec $EXEC $CONF --sentinel --pidfile $PIDFILE
         ;;
     stop)
         echo "Stopping $NAME PID: $PID ..."
         kill $PID
         ;;
     restart)
         echo "Restarting $NAME ..."
         $0 stop
         sleep 2
         $0 start
         ;;
     *)
         echo "Usage $0 {start|stop|restart}"
         ;;
esac

3) Sentinel の作業ディレクトリを生成し、Sentinel、Redis マスター・スレーブの各サービスを起動する。

mkdir /var/lib/redis/sentinel_26379

/etc/init.d/sentinel_26379 start

/etc/init.d/redis_6379 start

/etc/init.d/redis_6380 start

HAProxy と Redis による自動フェールオーバーが期待通りに動作するかテストを実施

別のコンソールから、tail -f /var/log/sentinel_26379.log で Sentinel のログメッセージを監視する。そして、redis_6379 のレプリケーション情報を確認する。

> redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

この例では、サーバーはマスターで、スレーブがない状態である。

sentinel_26379.log は、shows redis_6379 がマスターとして起動後、ODOWN 状態に陥っていることを示している。

...
26956:X 11 May 23:05:23.632 # -sdown master master01 ::1 6379
26956:X 11 May 23:05:23.632 # -odown master master01 ::1 6379

次のコマンドで、redis_6380 のレプリケーション情報を確認する。> redis-cli -p 6380 info replication

# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:42577
slave_priority:100
slave_read_only:1
connected_slaves:0
...

サーバーはリードオンリースレーブで、そのマスターは IP が 127.0.0.1 のホスト上にありポート番号が 6379  である。

Sentinel_26379.log は、スレーブ redis_6380 を見つけたことと、Sentinel 設定ファイルにマスター redis_6379 のスレーブとして登録したことを示している。

26956:X 11 May 23:07:34.172 * +slave slave [::1]:6380 ::1 6380 @ master01 ::1 6379
26956:X 11 May 23:07:44.244 * +fix-slave-config slave [::1]:6380 ::1 6380 @ master01 ::1 6379

もしもスレーブサーバーとして起動していない場合は、当該設定ファイルに以下のディレクティブを記述されていることを確認する。

     slaveof localhost 6379

その後、再起動を行う。以下のように、redis_6379 のレプリケーション情報を確認する。

> redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=60477,lag=1
master_repl_offset:60477
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:60476

この段階で、一組のマスターサーバーとスレーブサーバーが起動したことになる。

マスターサーバーのクラッシュをシミュレートして自動フェールオーバーのテストを行い、Sentinel により自動的にスレーブをマスターへ昇格させる

redis_6379 マスターを異常終了させる。

> redis-cli -p 6379 debug segfault 
Error: Server closed the connection

redis_6380 スレーブのレプリケーション情報を確認する。

> redis-cli -p 6380 info server
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

当該サーバーは接続中のスレーブがない状態でマスターに昇格していることが分かる。

Sentinel_26379.log は、マスターである redis_6379 がダウンしたので、スレーブであるredis_6380 サーバーをマスターへ昇格させて、接続中のスレーブがない状態に設定することによって、(クオラムが 1 であることを元に)フェールオーバーを実施していることを示している。また、Sentinel の設定を書き換え、ダウンしたマスターをスレーブと設定し、スレーブである redis_6380 を新規マスターとしている。

26956:X 11 May 23:09:52.566 # +sdown master master01 ::1 6379
26956:X 11 May 23:09:52.566 # +odown master master01 ::1 6379 #quorum 1/1
26956:X 11 May 23:09:52.566 # +new-epoch 5
26956:X 11 May 23:09:52.566 # +try-failover master master01 ::1 6379
26956:X 11 May 23:09:52.571 # +vote-for-leader 49c1cc2d0492c9bf60ad0dfc8258ee01986fae4b 5
26956:X 11 May 23:09:52.571 # +elected-leader master master01 ::1 6379
26956:X 11 May 23:09:52.571 # +failover-state-select-slave master master01 ::1 6379
26956:X 11 May 23:09:52.633 # +selected-slave slave [::1]:6380 ::1 6380 @ master01 ::1 6379
26956:X 11 May 23:09:52.634 * +failover-state-send-slaveof-noone slave [::1]:6380 ::1 6380 @ master01 ::1 6379
26956:X 11 May 23:09:52.717 * +failover-state-wait-promotion slave [::1]:6380 ::1 6380 @ master01 ::1 6379
26956:X 11 May 23:09:53.621 # +promoted-slave slave [::1]:6380 ::1 6380 @ master01 ::1 6379
26956:X 11 May 23:09:53.622 # +failover-state-reconf-slaves master master01 ::1 6379
26956:X 11 May 23:09:53.692 # +failover-end master master01 ::1 6379
26956:X 11 May 23:09:53.692 # +switch-master master01 ::1 6379 ::1 6380
26956:X 11 May 23:09:53.693 * +slave slave [::1]:6379 ::1 6379 @ master01 ::1 6380
26956:X 11 May 23:09:56.726 # +sdown slave [::1]:6379 ::1 6379 @ master01 ::1 6380

問題を修正し、クラッシュした redis_6379 を起動すると、スレーブとして稼働し、redis_6380 マスターに自動的に追加される。

> /etc/init.d/redis/redis_6379 start

数秒待ってから、サーバーレプリケーション情報を確認する。

> redis-cli -p 6379 info replication
# Replication
role:slave
master_host:::1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:4122
slave_priority:100
slave_read_only:1
connected_slaves:0
...

Sentinel のログによると、redis_6380 マスターサーバーのスレーブとして、認識・設定変更されていることが分かる。

26956:X 11 May 23:23:59.963 # -sdown slave [::1]:6379 ::1 6379 @ master01 ::1 6380
26956:X 11 May 23:24:09.944 * +convert-to-slave slave [::1]:6379 ::1 6379 @ master01 ::1 6380

redis_6380 のレプリケーション情報を確認する。

> redis-cli -p 6380 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=::1,port=6379,state=online,offset=61410,lag=1
master_repl_offset:61410
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:61409

新規にフェールオーバーされたマスターサーバーは、redis_6379 スレーブが接続した状態となっていることが分かる。また、Sentinel が 26379 番ポート経由で Redis マスター・スレーブサーバーを監視・管理していることが分かる。例えば、全ての監視対象マスターとその状態を出力してみる。

> redis-cli -p 26379 sentinel masters
1) 1) "name"
2) "master01"
3) "ip"
4) "::1"
5) "port"
6) "6380"
7) "runid"
8) "d43ff591a1fe556fcd345eb462588c6570c47df5"
9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "278"
17) "last-ping-reply"
18) "278"
19) "down-after-milliseconds"
20) "3000"
21) "info-refresh"
22) "3451"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "1159212"
27) "config-epoch"
28) "5"
29) "num-slaves"
30) "1"
31) "num-other-sentinels"
32) "0"360
33) "quorum"
34) "1"
35) "failover-timeout"
36) "9000"
37) "parallel-syncs"
38) "1"

他の Sentinel コマンドに関しては http://redis.io/topics/sentinel-clients を参照のこと。 

HAProxy、Sentinel そして自動フェールオーバー設定を行った Redis HA が正しく動作するかどうか確認のため、もう一度テストを実施 

別コンソールから、redis-cli クライアントを用いて、6378 番ポートでリスンする HAProxy サーバー経由でマスター Redis に接続し、レプリケーション情報を二秒ごとに取得する。

> while true; do redis-cli -p 6378 info replication; redis-cli -p 6378 info server | grep tcp_port; sleep 2; clear; done

# Replication
role:master
connected_slaves:1
slave0:ip=::1,port=6380,state=online,offset=1741860,lag=0
master_repl_offset:1741860
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:693285
repl_backlog_histlen:1048576

tcp_port:6380

ここでは、HAProxy 経由で、マスターである redis_6380 のレプリケーション情報を取得していることに注意。このマスターを異常停止させて、自動フェールオーバーが動作し、新規マスターに接続可能となるかどうか確認する。また別のコンソールで、マスターを異常停止させる。

> redis-cli -p 6380 debug segfault
Error: Server closed the connection

rdis-cli クライアントで HAProxy への定期接続を実行している元のコンソールに戻ると、以下が出力されていることが分かる。

Error: Server closed the connection

これは、6380 番ポートで稼働するマスターがダウンしていることを示している。数秒後、自動フェールオーバーが完了し、6379 番ポートで稼働する新規に昇格したマスターサーバーに接続し、以下のようなレプリケーション情報を取得するようになるはずである。

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
tcp_port:6379

ここで、異常終了させた redis_6380 を再起動する。

/etc/init.d/redis_6380 start

スレーブとして新規マスターに自動的に追加される。

# Replication
role:master
connected_slaves:1
slave0:ip=::1,port=6380,state=online,offset=1282,lag=1
master_repl_offset:1405
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:1404
tcp_port:6379

これで、自動フェールオーバー機構に Sentinel を用いた HA 構成実現のため、HAProxy と Redis マスター・スレーブレプリカを設定することに成功したと言える。

追加情報

コメント

Powered by Zendesk