*Redis Sentinel ドキュメント

Redis Sentinel はRedisに高可用性を提供します。実際的にはSentinelを使用すると特定の種類の障害に対して人手を介さずに抵抗するRedis配備を作成することができます。

Redis Sentinelは監視、通知のようなその他の付随タスクも提供し、クライアントの構成プロバイダとして機能します。

これは巨視レベル (つまり全体像)でのSentinelの機能の完全な一覧です:

  • 監視。Sentinel はマスターとレプリカインスタンスが期待通りに動作しているかを常にチェックします。
  • 通知。Sentinel は監視されているRedisインスタンスの1つに何か問題があることを、APIを使ってシステム管理者、他のコンピュータプログラムに通知することができます。
  • 自動フェイルオーバー。マスターが期待通りに動作していない場合、Sentinel はレプリカがマスターに昇格し、他の追加のレプリカが新しいマスターを利用するように設定され、Redisサーバを使っているアプリケーションが接続時に新しいアドレスを使うように伝えられる、フェイルオーバープロセスを開始することができます。
  • 構成プロバイダ. Sentinel はクライアントのサービス検出のための権限のソースとして振舞います: クライアントは特定のサービスを担当する現在のRedisマスターのアドレスを要求するためにSentinelに接続します。フェイルオーバーが発生するとSentinelは新しいアドレスを報告します。

*Sentinel の分散性

Redis Sentinel は分散システムです:

Sentinel 自身は複数のSentinelプロセスが連携して動作するように設計されています。複数のSentinelプロセスを連携する利点は以下の通りです:

  1. 障害の検知は複数のSentinelが指定されたマスターがもう使用できないという事実に同意した時に行われます。これは誤検知の可能性を低くします。
  2. 全ての Sentinel が動作していなくても Sentinel は動作し、システムを障害に対して堅牢にします。結局のところ、それ自身が単一障害点であるフェイルオーバーシステムを持つことは楽しくありません。

Sentinels、Redis インスタンス (マスターとレプリカ) および Sentinel と Redis に接続しているクライアントの全体も、特定のプロパティを持つ大規模な分散システムです。この文章では、Sentinelの基本的なプロパティを理解するために必要な基本的な情報から、Sentinel がどのように動作するかを理解するためのより複雑な情報(オプション)までを、徐々に紹介します。

*クイック スタート

*Sentinel の入手

Sentinel の現在のバージョンは Sentinel 2 です。これは、より強力で予測が簡単なアルゴリズム(このドキュメントで説明されます)を使った初期のSentinel実装の書き直しです。

安定版の Redis Sentinel は Redis 2.8 から出荷されています。

新しい開発は不安定版ブランチで行われ、新しい機能は安定したと見なされ次第最新の安定版ブランチに移植されることがあります。

Redis 2.6 に同梱されている Redis Sentinel バージョン 1 は非推奨で使うべきではありません。

*Sentinel の実行

redis-sentinel の実行可能ファイルを使用している場合 (あるいは redis-server 実行可能ファイルの名前のシンボリックリングがある場合)、以下のコマンドを使って Sentinel を実行することができます:

redis-sentinel /path/to/sentinel.conf

それ以外の場合は、Sentinel モードで起動したredis-server実行可能ファイルを直接使うことができます:

redis-server /path/to/sentinel.conf --sentinel

どちらの方法でも同じように機能します。

しかし、設定ファイルは再起動の際に再ロードされる現在の状態を保存するためにシステムによって使用されるため、Sentinel の実行時に設定ファイルを使うことは必須です。設定ファイルが指定されていない場合、あるいは設定ファイルのパスが書き込み可能ではない場合、Sentinel は単に起動を拒否します。

Sentinel はデフォルトでTCP ポート 26379 への接続をlistenするため、Sentinel が機能するためには、他のSentinelインスタンスのIPアドレスからの接続を受信するためにサーバのポート 26379 が開いていなければなりません。そうでなければ、Sentinel は何をするかについて話したり同意することができないため、フェイルオーバーは実行されません。

*配備前にSentinelについて知っておくべき基本事項

  1. 堅牢な配備のために少なくとも3つのSentinelインスタンスが必要です。
  2. 3つのSentinel インスタンスは独立して失敗すると考えられているコンピュータあるいは仮想マシーンに配置される必要があります。つまり、例えば異なる物理サーバあるいは異なる可用性ゾーン上の仮想マシーン。
  3. Redis は非同期リプリケーションを使用するため、Sentinel + Redis 分散システムは通知された書き込みが失敗しても保持されることを保証しません。ただし、配備するにはより安全ではない方法ですが、書き込みを失うウィンドウを特定の瞬間に限定するようにSentinelを配備する方法があります。
  4. クライアントでSentinelのサポートが必要です。一般的なクライアント ライブラリはSentinelをサポートしますが、全てではありません。
  5. 開発環境で時々テストしない場合に安全なHAセットアップはありません。また、本番環境でテストできる場合でそれらが動作する場合は、さらに優れています。手遅れになった時(ますたーが機能しなくなった午前3時)のみ明らかになる設定ミスがあるかもしれません。
  6. Sentinel、Docker あるいはその他の形式のネットワークアドレス変換またはポートマッピングは慎重に混在させる必要があります: Docker はポートマッピングを行い、Sentinelによる他のSentinelプロセスの自動検出およびマスターのレプリカのリストを破壊します。詳細な情報はこのドキュメントの後のSentinelとDockerについての章を調べてください。

*Sentinel の設定

Redisのソース配布物には、Sentinelを設定するために使うことができる自己文章化された設定ファイルの例であるsentinel.conf が含まれますが、一般的な最小設定は以下のようになります:

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5

監視するマスターを指定するだけで、個々のマスター(任意の数のレプリカを持つことができます)に異なる名前をつけることができます。レプリカを指定する必要はありません。自動的に検出されます。Sentinel は(再起動の際に情報を保持するために)レプリカについての追加の情報と一緒に設定を自動的に更新します。フェイルオーバー中にレプリカがマスターに昇格する度、および新しいSentinelが検出される度に、設定も上書きされます。

上記の設定例では、基本的に2組のRedisインスタンスを監視します。それぞれがマスターと未定義の数のレプリカで構成されます。1セットのインスタンスは mymaster と呼ばれ、もう1つは resque と呼ばれます。

sentinel monitor 構文の引数の意味は以下の通りです:

sentinel monitor <master-group-name> <ip> <port> <quorum>

明確にするために、設定オプションの意味を1行ずつ確認しましょう:

最初の行は、2の定足数を持ち、アドレス 127.0.0.1とポート 6379 にあるmymasterと呼ばれるマスターを監視するように指示します。quorum 引数以外はとても明確です:

  • 定足数は、実際にマスタを障害だとマークし可能であればフェイルオーバーの手順を開始するために、マスターが到達不可能だという事実に同意する必要があるSentinelの数です。
  • ただし、定足数は障害を検知するためだけに使われます。実際にフェイルオーバーを行うには、Sentinelのうちの1つがフェイルオーバーのリーダーに選出され、続行を承認される必要があります。これはSentinelプロセスの大多数の投票により起こります。

つまり、例えば5つのSentinelプロセスがあり、特定のマスターの定足数が2の値に設定されている場合は、以下のことが起こります:

  • 2つのSentinelが同時にマスターに到達できないことに同意した場合、2つのうちの1つがフェイルオーバーを開始しようとします。
  • 到達可能なSentinelが合計で少なくとも3つある場合、フェイルオーバーは承認され、実際に開始されます。

実際的には、障害の間もしSentinel プロセスの大多数が通信することができない場合 Sentinel はフェイルオーバーを開始しない (別名 少数パーティションではフェイルオーバー無し) ことを意味します。

*他の Sentinel のオプション

他のオプションはほとんどの場合以下の形式です:

sentinel <option_name> <master_name> <option_value>

そして以下の目的で使用されます:

  • down-after-milliseconds は、Sentinelがインスタンスがダウンしていると判断し始めるために、インスタンスが到達不可能でなければならない(PINGに応答しないかエラーで応答する)ミリ秒単位の時間です。
  • parallel-syncs はフェイルオーバー後に新しいマスターを使うために同時に再設定することができるレプリカの数を設定します。数値が小さいほどフェイルオーバーのプロセスが完了するまでの時間が長くなりますが、もしレプリカが古いデータを処理するように構成されている場合、全てのレプリカが同時にマスターと再同期したくないかもしれません。レプリケーション プロセスはほとんどレプリカに対してブロッキングしませんが、マスターからバルクデータをロードするために停止する瞬間があります。このオプションの値を1に設定することで、一度に1つのレプリカだけが到達不可能に確実にしたいかもしれません。

追加のオプションはこの文章の残りの部分で説明され、Redis配布物に同梱されているサンプルの sentinel.conf ファイルの中に記載されています。

全ての構成パラメータは SENTINEL SET コマンドを使って実行時に修正することができます。詳細は実行時のSentinelの再設定の章を見てください。

*Sentinel 配備の例

これでSentinelの基本的な情報について分かったので、Sentinel プロセスをどこに配置すればいいか、どれだけのSentinel プロセスが必要なのかなどを知りたいと思うかもしれません。この章では幾つかの配備例を示します。

設定例をグラフィカル形式で表示するために ASCII アートを使用します。以下は様々な記号の意味です:

+--------------------+
| This is a computer |
| or VM that fails   |
| independently. We  |
| call it a "box"    |
+--------------------+

実行中のボックス内に書き込みます:

+-------------------+
| Redis master M1   |
| Redis Sentinel S1 |
+-------------------+

通信ができることを示すために、個別のボックスが線で接続されます:

+-------------+               +-------------+
| Sentinel S1 |---------------| Sentinel S2 |
+-------------+               +-------------+

ネットワーク パーティションはスラッシュを使って中断された線として示されます:

+-------------+                +-------------+
| Sentinel S1 |------ // ------| Sentinel S2 |
+-------------+                +-------------+

また、以下のことに注意してください:

  • マスターは M1, M2, M3, ..., Mn と呼ばれます。
  • レプリカは R1, R2, R3, ..., Rn と呼ばれます (R は レプリカ を表します)。
  • Sentinel は S1, S2, S3, ..., Sn と呼ばれます。
  • クライアントは C1, C2, C3, ..., Cn と呼ばれます。
  • Sentinel のアクションによってインスタンスが役割を変更した時に角括弧で囲みます。つまり [M1] はSentinelの介入のために現在マスターになっているインスタンスを意味します。

Sentinel はフェイルオーバーを開始するために常に大多数と通信する必要があるため、Sentinelが2つしか使用されていないセットアップは表示しません。

*例 1: 2つだけの Sentinel。これは使わないでください

+----+         +----+
| M1 |---------| R1 |
| S1 |         | S2 |
+----+         +----+

Configuration: quorum = 1
  • このセットアップでは、もしマスター M1 に障害が起きた時に、2つのSentinelが障害について合意に達することができ(当然定足数は1に設定)、大多数が2のためフェイルオーバーも承認されるため、R1 は昇格されるでしょう。したがって表面的には動作する可能性がありますが、なぜこのセットアップが壊れているかを見るために次の点を確認してください。
  • M1 が稼働中のボックスが停止すると、S1 の動作も停止します。もう一方のボックス S2 で実行中の Sentinel はフェイルオーバーを認証できないため、システムは利用不可になります。

様々なフェイルオーバーを命令し、後で全ての Sentinel に最新の構成を伝播するには、過半数が必要なことに注意してください。また、上のセットアップの片側で同意無しにフェイルオーバーを実行することは非常に危険なことに注意してください:

+----+           +------+
| M1 |----//-----| [M1] |
| S1 |           | S2   |
+----+           +------+

上の設定では、完全に対称的な方法で2つのマスター(S2は承認無しにフェイルオーバーできると仮定)を作成しました。クライアントは無期限に両方に書き込む可能性があり、永続的なスプリットブレイン状態を避けるためにどの設定が正しいかをパーティションが修復した時に知る方法はありません。

したがって、常に3つの異なるボックスに少なくとも3つのSentinelを配備してください。

*例 2: 3つのボックスの基本的なセットアップ

これはとても単純なセットアップで、安全性を高めるために調整が簡単であるという利点があります。各ボックスはRedisプロセスとSentinelプロセスを実行している、3つのボックスに基づいています。

       +----+
       | M1 |
       | S1 |
       +----+
          |
+----+    |    +----+
| R2 |----+----| R3 |
| S2 |         | S3 |
+----+         +----+

Configuration: quorum = 2

もしマスター M1 が障害を起こすと、S3 は障害について同意し、フェイルオーバーを許可してクライアントを続行できるようにします。

すべての Sentinel セットアップで、Redis は非同期レプリケーションを使うため、特定の確認済み書き込みがマスタに昇格したレプリカに到達できない可能性があるため、一部の書き込みが失われるリスクが常にあります。ただし上のセットアップでは、以下の図のようにクライアントが古いマスターと分離されているため、リスクが高くなります:

         +----+
         | M1 |
         | S1 | <- C1 (writes will be lost)
         +----+
            |
            /
            /
+------+    |    +----+
| [M2] |----+----| R3 |
| S2   |         | S3 |
+------+         +----+

この場合、ネットワーク パーティションは古いマスター M1 を分離したため、レプリカ R2 はマスターに昇格します。しかし、C1 のように古いマスターと同じパーティションにあるクライアントはデータを古いマスターに書き続けることがあります。パーティションが回復するとマスターは新しいマスターのレプリカとして再設定され、そのデータセットが破棄されるため、このデータは永久に失われるでしょう。

この問題は、もしマスターが指定された数のレプリカに書き込みを転送できなくなったことを検知すると書き込みの受け入れを停止する以下のRedisのレプリケーション機能を使うことで緩和することができます。

min-replicas-to-write 1
min-replicas-max-lag 10

上の設定(詳細はRedis配布物の中の自己コメントされたredis.confの例を参照してください)で、Redisインスタンスはマスターとして動作しているとき、少なくとも1つのレプリカに書き込めない場合は書き込みを受け付けなくなります。レプリケーションは非同期のため、実際に書き込みができないということは、レプリカが切断されているか、指定された max-lag 秒以上の間非同期の確認応答を送信していないことを意味します。

この設定を使うと、上の例の古いRedisマスター M1 は10秒後に使えなくなります。パーティションが回復すると、Sentinelは新しい設定に収束し、クライアント C1 は有効な設定を取得して新しいマスタを使って続行できます。

しかし、無料のランチはありません。この改良により、もし2つのレプリカがダウンすると、マスターは書き込みの受付を停止します。それはトレードオフです。

*例 3: クライアント ボックス内の Sentinel

1つはマスターもう一つはレプリカの2つのRedisボックスだけが利用可能な場合があります。例 2 の設定はその場合には実用的ではないため、Sentinelがクライアントの場所に配置される以下のような手段をとることができます:

            +----+         +----+
            | M1 |----+----| R1 |
            |    |    |    |    |
            +----+    |    +----+
                      |
         +------------+------------+
         |            |            |
         |            |            |
      +----+        +----+      +----+
      | C1 |        | C2 |      | C3 |
      | S1 |        | S2 |      | S3 |
      +----+        +----+      +----+

      Configuration: quorum = 2

このセットアップでは、Sentinelの視点はクライアントのものと同じです: もしマスターがクライアントの多数から到達可能であれば、それで問題ありません。ここで C1, C2, C3 は一般的なクライアントで、C1 がRedisに接続している単一のクライアントを識別すると意味ではありません。それは、アプリケーションサーバ、Railsアプリケーションあるいはそのようなものに近いです。

M1 と S1 が動作しているボックスに障害が発生すると、問題なくフェイルオーバーが起こりますが、ネットワーク パーティションが異なると異なる挙動になることが分かります例えば、もしクライアントとRedisサーバ間のネットワークが切断された場合、Redisマスターとレプリカの両方が利用できないため、Sentinelはセットアップできません。

C3がM1で分割された場合(上で説明したネットワークではほとんど不可能ですが、異なるレイアウトあるいはソフトウェア層での障害の場合には可能性が高いです)、例2で説明したものと似た問題があります。ここではレプリカとマスターだけが存在するため、対称性を破る方法はありません。マスターはレプリカから切断されたときにクエリの受け入れを止めることができません。そうでなければ、マスターはレプリカの障害時に利用することができません。

従ってこれは有効なセットアップですが、例2のセットアップはRedisと同じボックス内で実行されるRedisのHAシステムが管理しやすくなり、少数のパーティションへのマスターの書き込みに総時間の制限を付けることができるという利点があります。

*例4: 3つ未満のクライアントを持つSentinel クライアント側

例3で説明したセットアップは、クライアント側に3未満のボックスがある場合(例えば、3つのWebサーバ)は利用できません。この場合、次のような混在したセットアップに頼る必要があります:

            +----+         +----+
            | M1 |----+----| R1 |
            | S1 |    |    | S2 |
            +----+    |    +----+
                      |
               +------+-----+
               |            |
               |            |
            +----+        +----+
            | C1 |        | C2 |
            | S3 |        | S4 |
            +----+        +----+

      Configuration: quorum = 3

これは例3のセットアップに似ていますが、ここでは利用可能な4つのボックスに4つのSentinelを実行します。もしマスタ M1が利用できなくなると、他の3つのSentinelがフェイルオーバを実行します。

理論的にはこのセットアップはC2とC4を実行しているボックスを削除し、定足数2を設定することで動作します。しかしアプリケーション層に高可用性を持たせずにHAをRedis側に期待することはほとんどありません。

*Sentinel, Docker, NAT と起こりえる問題

Docker はポートマッピングと呼ばれる手法を使います: Dockerのコンテナ内で実行しているプログラムはプログラムが使用していると思っているものとは異なるポートで公開される可能性があります。これは同じサーバ内で同時に同じポートを使って複数のコンテナを実行するのに役立ちます。

Dockerはこれだけのソフトウェア システムではありません。ポートが再マップされるかもしれない他のネットワークアドレスセットアップがあり、時にはポートだけではなくIPアドレスもあります。

ポートとアドレスの再マップはSentinelに2つの問題を起こします。

  1. Sentinelの他のSentinelの自動検出はもう動作しません。これは各Sentinelが接続を待機しているポートとアドレスをアナウンスするhelloメッセージに基づいているからです。しかし、Sentinelは再マップされているアドレスあるいはポートを知る方法がないため、他のSentinelが接続するには正しくない情報を発表しています。
  2. レプリカは似たような方法でRedis マスタのINFO出力内にリストされています: アドレスはTCP接続のリモートピアをチェックするマスターによって検出されますが、ポートはハンドシェイク中にレプリカによって広告されます。ただしポイント1で公開されているのと同じ理由でポートは間違っています。

Sentinel はマスターの INFO 出力情報を使ってレプリカを自動検出するため、検出されたレプリカは到達不能になり、Sentinelはマスターをフェイルオーバできません。システムの観点から良いレプリカはないため、Dockertと一緒に配備されたマスターとレプリカインスタンスのセットを監視する方法は Docker にポートを 1:1 にマッピングするように指示しない限り、現在のところありません.

最初の問題として、転送されたポート(あるいはポートが再マップされる他のNAT設定)を持つDockerを使ってSentinelのインスタンスのセットを実行したい場合、Sentinelに次の2つのSentinel設定ディレクティブを使ってSentinelに特定のIPとポートのセットをアナウンスさせることができます。

sentinel announce-ip <ip>
sentinel announce-port <port>

Docker にはホット ネットワーク モードで実行する機能があることに注意してください (詳細な情報は--net=hostオプションを確認してください)。このセットアップではポートが再マップされないので、問題にならないはずです。

*クイック チュートリアル

このドキュメントの次の章では、Sentinel API、設定およびセマンティクスに関する全ての詳細について、段階的に説明します。ただしできるだけ早くシステムを使用したい人のために、この章は3つのSentinelインスタンスを設定してやりとりをする方法を示すチュートリアルです。

ここで、インスタンスがポート 5000, 5001, 5002 で実行されていると仮定します。またポート6379でRedisマスタが実行中で、ポート6380でレプリカが実行中だと仮定します。このチュートリアル中では IPv4 ループバック アドレス 127.0.0.1 を使い、パーソナルコンピュータ内でシミュレーションを実行していると仮定します。

3つのSentinel設定ファイルは、以下の通りに見えるはずです:

port 5000
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

他の2つの設定ファイルは同じですが、ポート番号として 5001 と 5002 を使っています。

上の設定について注意すべき点が幾つかあります:

  • マスターセットは mymasterと呼ばれます。それはマスターとレプリカを識別します。各 マスターセット は異なる名前を持つため、Sentinel は同時に異なるマスターとレプリカのセットを監視することができます。
  • 定足数は2の値 (sentinel monitor 構成ディレクティブの最後の引数)。
  • down-after-milliseconds 値は 5000 ミリ秒、つまり5秒で、この時間内にpingからの応答がないとマスターはすぐに失敗したと検出されます。

3つのSentinelを開始すると、それらが記録する幾つかのメッセージが以下のように表示されます:

+monitor master mymaster 127.0.0.1 6379 quorum 2

これは Sentinel のイベントで、後で指定するイベント名をSUBSCRIBE すると、Pub/Sub経由でこの種類のイベントを受け取ることができます。

Sentinel は障害検出時とフェイルオーバー時に様々なイベントを生成して記録します。

*Sentinel にマスターの状態について尋ねる

Sentinel を使用して開始する最も明らかな事は、監視しているマスタがうまく行っているかどうかを確認することがです:

$ redis-cli -p 5000
127.0.0.1:5000> sentinel master mymaster
 1) "name"
 2) "mymaster"
 3) "ip"
 4) "127.0.0.1"
 5) "port"
 6) "6379"
 7) "runid"
 8) "953ae6a589449c13ddefaee3538d356d287f509b"
 9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "735"
19) "last-ping-reply"
20) "735"
21) "down-after-milliseconds"
22) "5000"
23) "info-refresh"
24) "126"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "532439"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "60000"
39) "parallel-syncs"
40) "1"

御覧の通り、マスタについての多く情報が出力されます。私たちにとって特に興味深いものが幾つかあります:

  1. num-other-sentinels は2です。つまりSentinelはすでにこのマスタのSentinelを2つ検出し他ことが分ります。ログを確認すると、+sentinel イベントが生成されていることが分ります。
  2. flags は単なる master です。マスタがダウンすると、ここにも s_down あるいは o_down フラグが表示されることが期待されます。
  3. num-slaves は正しく1に設定されているので、Sentinelはマスタにアタッチされたレプリカがあることも検出しました。

このインスタンスについて詳しく調べるには、以下の2つのコマンドを試してください:

SENTINEL replicas mymaster
SENTINEL sentinels mymaster

最初のものはマスタに接続しているレプリカについての同様の情報を提供し、2つ目は他のSentinelに関する情報を提供します。

*現在のマスタのアドレスを取得する

既に指定したようにSentinelはマスタとレプリカの接続したいクラインとの設定プロバイダとしても動作します。フェイルオーバーや採光性が発生する可能性があるため、クライアントは特定のインスタンスのセットに対して現在アクティブなマスタが誰なのか分からないため、Sentinelは次の質問をするためにAPIをエクスポートします:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"

*フェイルオーバーのテスト

この時点で、私たちのおもちゃのSentinel配備はテストする準備ができています。マスターをKillして設定が変更されるかを確認するだけです。そうするには、単に以下のことをします:

redis-cli -p 6379 DEBUG sleep 30

このコマンドは30秒間スリープしてマスタにもう到達できないようにします。それは基本的にマスタが何かの理由でハングしていることをシミュレートします。

Sentinelのログを調べると、多くのアクションを見ることができるはずです:

  1. 各Sentinelはマスタが +sdown イベントでダウンしたことを検知します。
  2. このイベントは後で +odown に昇格されます。それは複数のSentinelがマスタが到達不可能である事実に同意したことを意味します。
  3. Sentinel は最初のフィルオーバーの試行を開始するSentinelに投票します。
  4. フェイルオーバーが発生します。

mymasterの現在のアドレスがどれであるかを再び尋ねると、今回は結果的に異なる応答を取得するはずです:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380"

今のところ順調です... この時点で、Sentinelの配備を作成するためにジャンプするか、すべてのSentinelコマンドと内部を理解するためにもっと読むことができます。

*Sentinel API

Sentinelは状態を検査し、監視されているマスタとレプリカの状態をチェックし、特定の通知を受信するために購読し、実行時にSentinelの設定を変更するためのAPIを提供します。

デフォルトでは、SentinelはTCPポート 26379 (6379 は通常のRedisポートであることに注意してください)を使って実行されます。SentinelはRedisプロトコルを使ったコマンドを受け付けます。つまり、Sentinelとやりとりをするために redis-cli あるいは他の未修正のRedisクライアントを使うことができます。

監視対象のRedisインスタンスがどのような状態であるかをその観点から調べたり、他のSentinelが認識していることなどを確認するために、直接Sentinelに尋ねることができます。あるいは、Pub/Subを使って、フェイルオーバーあるいはインスタンスがエラー状態になったなど、各イベントが発生する度に push形式の通知をSentinelから受信することができます。

*Sentinel コマンド

以下は、Sentinelの設定をするために使われるコマンドとして説明されていない、後で説明される、使用可能なコマンドのリストです。

  • PING このコマンドは単純に PONG を返します。
  • SENTINEL masters 監視されているマスタのリストとそれらの状態を表示します。
  • SENTINEL master <master name> 特定のマスタの状態と情報を表示します。
  • SENTINEL replicas <master name> このマスタのレプリカのリストとそれらの状態を返します。
  • SENTINEL sentinels <master name> このマスタのsentinelインスタンスのリストとそれらの状態を返します。
  • SENTINEL get-master-addr-by-name <master name> マスタのipとport番号を名前と一緒に返します。このマスタについてフェイルオーバーが進行中あるいは正常に終了した場合は、昇格したレプリカのアドレスとポートを返します。
  • SENTINEL reset <pattern> このコマンドは名前に一致するすべてのマスタを再設定します。パターン引数は glob 形式のパターンです。再設定プロセスはマスタ内(フェイルオーバー進行中も含む)の以前の状態をクリアし、既に検出されマスタに関連付けられている全てのレプリカとsentinelを削除します。
  • SENTINEL failover <master name> 他のSentinelに同意を求めることなく、マスタが到達不可能であるかのようにフェイルオーバーを強制します(ただし、他のSentinelがそれらの設定を更新するように新しいバージョンの設定が発行されます)。
  • SENTINEL ckquorum <master name> 現在のSentinelの設定がマスタのフェイルオーバーに必要な定足数に到達でき、フェイルオーバーを承認するのに必要な大多数に到達可能かどうかを調べます。このコマンドはSentinel配備がOKであるかどうかを調べるために監視システム内で使われるべきです。
  • SENTINEL flushconfig Sentinelに現在のSentinelの状態を含めて設定をディスクに書き換えるように強制します。通常Sentinelは(再起動後もディスクに保持される状態のサブセットのコンテキストで)状態に何か変更がある度に設定を書き換えます。ですが、操作エラー、ディスク障害、パッケージのアップグレードスクリプト、あるいは設定マネージャによって、設定ファイルが失われることがあります。そのような場合、Sentinelに設定ファイルの書き換えを強制する方法は便利です。このコマンドは以前の設定ファイルが完全に失われた場合でも動作します。

*実行時のSentinelの再設定

Redis バージョン 2.8.4 から、Sentinel は指定されたマスタの設定を追加、削除あるいは変更するためのAPIを提供します。複数のSentinelがある場合、Redis Sentinelを適切に動作させるには全てのインスタンスに変更を適用する必要があることに注意してください。 これは、1つのSentinelの設定の変更は自動的にはネットワーク内の他のSentinelに伝搬されない事を意味します。

以下はSentinelインスタンスの設定を更新するために使われる SENTINEL サブ コマンドのリストです。

  • SENTINEL MONITOR <name> <ip> <port> <quorum> このコマンドはSentinelに指定された名前、IP、ポートおよび定足数を持つ新しいマスタの監視を開始するように伝えます。ipとしてホスト名を使うことができずIPv4あるいはIPv6アドレスを提供する必要があるという違いはありますが、sentinel.conf 設定ファイル内のsentinel monitor設定ディレクティブと同じです。
  • SENTINEL REMOVE <name>は指定されたマスタを削除するために使われます: マスタはもう監視されず、Sentinelの内部状態から完全に削除されるため、SENTINEL masters などによって一覧表示されなくなります。
  • SENTINEL SET <name> <option> <value> SET コマンドはRedisのCONFIG SETにとても似ていて、特定のマスタの設定パラメータを変更するために使われます。複数のオプション / 値のペアを指定(あるいは全く無し)することができます。sentinel.confによって設定されるすべての構成パラメータも SET コマンドを使って設定可能です。

以下はobjects-cacheというマスタのdown-after-milliseconds設定を修正するための SENTINEL SETコマンドの例です:

SENTINEL SET objects-cache-master down-after-milliseconds 1000

既に述べたように、SENTINEL SETを使ってスタートアップ設定ファイルに設定可能なすべての設定パラメータを設定することができます。さらに、SENTINEL MONITORの後に SENTINEL REMOVEを続けることでマスタを削除および再追加すること無しに、マスタの定足数をたんに変更することができます。単に次のように使います:

SENTINEL SET objects-cache-master quorum 5

SENTINEL MASTER はすべての設定パラメータを解析しやすい形式(フィールド/値のペアの配列)で提供するため、GETコマンドと同等のものはないことに注意してください。

*Sentinel の追加と削除

Sentinelによって自動検出の機構が実装されているため、新しいSentinelを配備に追加することは簡単です。現在のアクティブなマスタを監視するように設定された新しいSentinelを起動するだけです。10秒以内に、Sentinelは他のSentinelのリストとマスタにアタッチされたレプリカのセットを取得します。

複数のSentinelを一度に追加する必要がある場合は、次のものを追加する前に最初の1つについて他の全てのSentinelが認識するのを待って、1つ1つ追加することをお勧めします。これは新しいSentinelを追加するプロセスで失敗が起きる可能性があるため、パーティションの片側でのみ多数決が行われないことを保証するためにも便利です。

これは新しいSentinelを30秒の遅延で追加し、ネットワークのパーティションが無い時に、簡単に実現できます。

プロセスの最後に、全てのSentinelがマスタを監視しているSentinelの総数について同意するかを確認するために、SENTINEL MASTER mastername コマンドを使うことができます。

Sentinelの削除はもう少し複雑です: フェイルオーバーの承認に必要な大多数と新しい設定の作成を動的に変更したくないため、たとえ長い間到達できないとしてもSentinelは既に認識したSentinelを忘れません。そのためSentinelを削除するには、ネットワークパーティションが無い場合は以下の手順を実行する必要があります:

  1. 削除したいSentinelのSentinelプロセスを停止します。
  2. 他の全てのSentinelインスタンスに SENTINEL RESET * コマンドを送信する (単に1つのマスタを再設定したい場合は、* の代わりに正確なマスタ名を使うことができます)。1つ1つ、インスタンス間で少なくとも30秒待ちます。
  3. 各SentinelのSENTINEL MASTER masternameの出力を調べて、全てのSentinelが現在アクティブなSentinelの数について一致していることを確認します。

*古いマスタまたは到達不能なレプリカの削除

Sentinel は、長い間到達できない場合でも、特定のマスタのレプリカを決して忘れません。Sentinelはネットワークパーティションあるいは障害の後で復帰中のレプリカを正しく再構成できなければならないので、これは便利です。

更にフェイルオーバー後にフェイルオーバーしたマスタは新しいマスタのレプリカとして仮想的に追加されます。これにより、新しいマスタが使用可能になるとすぐに複製されるように再構成されます。

ですが、Sentinelによって監視されているレプリカのリストから、永久にレプリカ(古いマスタかもしれません)を削除したい場合があります。

これを行うには、全てのSentinelに SENTINEL RESET mastername コマンドを送信する必要があります: それらは次の10秒以内に現在のマスタの INFO 出力から正しく複製された1つだけを追加してレプリカのリストを更新します。

*Pub/Sub メッセージ

チャンネルをSUBSCRIBE あるいは PSUBSCRIBEし、特定のイベントについての通知を受けるために、クラインとはSentinelを Redis 互換の Pub/Sub サーバ (ただしPUBLISHを使うことはできません)であるかのように使うことができます。

チャンネル名はイベントの名前と同じです。例えば+sdownという名前のチャンネルは SDOWN (SDOWN は問い合わせをしているSentinelの観点からはインスタンスにアクセスできなくなることを意味します)に入る全てのインスタンスに関するすべての通知を受信します。

全てのメッセージを取得するには PSUBSCRIBE *を使用して単純に購読するだけです。

以下はこのAPIを使って受け取ることができるチャンネルとメッセージのフォーマットのリストです。最初の単語はチャンネル/イベント名で、残りはデータのフォーマットです。

注意: instance details が指定されている場合は、続く引数がターゲットのインスタンスを識別するために提供されます:

<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

マスターを識別する部分 (@ 引数から最後まで) はオプションで、インスタンスがマスター自身ではない場合にのみ指定されます。

  • +reset-master <instance details> -- マスターは再設定されました。
  • +slave <instance details> -- 新しいレプリカが検知されアタッチされました。
  • +failover-state-reconf-slaves <instance details> -- フェイルオーバー状態が reconf-slaves 状態に変更されました。
  • +failover-detected <instance details> -- 他のSentinelあるいは外部のエンティティによって開始されたフェイルオーバーが検知されました (アタッチされたレプリカがマスターになりました)。
  • +slave-reconf-sent <instance details> -- sentinelのリーダーが新しいレプリカのために再構成をするためにREPLICAOF コマンドをこのインスタンスに送信しました。
  • +slave-reconf-inprog <instance details> -- 再構成されたレプリカは新しいマスタ ip:port ペアのレプリカとなるために現れましたが、同期プロセスはまだ完了していません。
  • +slave-reconf-done <instance details> -- レプリカが新しいマスタと同期しています。
  • -dup-sentinel <instance details> -- 指定されたマスタの1つ以上のsentinelが重複しているとして削除されました (これは例えばSentinelインスタンスが再起動された時に起こります)。
  • +sentinel <instance details> -- このマスタの新しいsentinelが検知されアタッチされました。
  • +sdown <instance details> -- 指定されたインスタンスは今では Subjectively Down 状態にあります。
  • -sdown <instance details> -- 指定されたインスタンスはもう Subjectively Down 状態にありません。
  • +odown <instance details> -- 指定されたインスタンスは今では Objectively Down 状態にあります。
  • -odown <instance details> -- 指定されたインスタンスはもう Objectively Down 状態ではありません。
  • +new-epoch <instance details> -- 現在のエポックが更新されました。
  • +try-failover <instance details> -- 新しいフェイルオーバーが進捗中で、大多数によって選出されるのを待っています。
  • +elected-leader <instance details> -- 指定されたエポックについて選出を獲得し、フェイルオーバーすることができます。
  • +failover-state-select-slave <instance details> -- 新しいフェイルオーバーの状態がselect-slaveです: 昇格のための適切なレプリカを見つけようとしています。
  • no-good-slave <instance details> -- 昇格するための良いレプリカがありません。現在のところいつか後で試行するつもりですが、おそらくこれは変更され、この場合状態マシーンは完全にフェイルオーバーを中止するでしょう。
  • selected-slave <instance details> -- 昇格するための指定された良いレプリカを見つけました。
  • failover-state-send-slaveof-noone <instance details> -- マスターとして昇格されたレプリカを再構成しようとして、切り替えるのを待っています。
  • failover-end-for-timeout <instance details> -- フェイルオーバーがタイムアウトのために中止され、レプリカは結果的に新しいマスタを複製するためにどうにか設定されます。
  • failover-end <instance details> -- フェイルオーバーが無事中止されました。全てのレプリカは新しいマスタを複製するために再設定されているようです。
  • switch-master <master name> <oldip> <oldport> <newip> <newport> -- 設定が変更された後でマスタの新しいIPとアドレスが指定されたものになります。これは ほとんどの外部ユーザが興味があるメッセージです。
  • +tilt -- チルト モードに入りました。
  • -tilt -- チルトモードを抜けました。

* -BUSY 状態の処理

Luaスクリプトの時間制限と設定された以上の時間Luaスクリプトが実行中の場合に、Redisインスタンスによって返される -BUSY エラー。フェイルオーバーを引き起こす前にこれが起きた場合、Redis SentinelはSCRIPT KILL コマンドを送信しようとします。これはスクリプトが読み取り専用の場合にのみ成功します。

この試行の後でインスタンスがまだエラー状態の場合、結果的にフェイルオーバーされるでしょう。

*レプリカの優先度

Redis インスタンスはreplica-priorityと呼ばれる設定パラメータを持ちます。この情報は、Redis レプリカインスタンスによって INFO 出力に公開され、Sentinel はそれを使ってマスタをフェイルオーバーするために使えるレプリカの中からレプリカを選択します:

  1. レプリカの優先度が 0 に設定されている場合、レプリカはマスタに昇格されません。
  2. Sentinel は 優先順位番号が低いレプリカを優先します。

例えば、現在のマスタと同じデータセンタにレプリカ S1 があり、別のデータセンタに別のレプリカ S2 がある場合、S1 に優先度 10 を設定し、S2 に優先度 100 を設定できます。マスタに障害が発生し、S1 と S2 の両方が利用可能な場合、S1 が優先されます。

レプリカが選択される方法についての詳細は、このドキュメントのレプリカの選択と優先度のセクションを確認してください。

*Sentinel と Redis 認証

マスタがクライアントからのパスワードを要求するように設定されている場合、セキュリティ対策として、レプリカはマスタで認証し、非同期レプリケーションプロトコルに使われるマスタとレプリカの接続を作成するために、このパスワードも認識する必要があります。

これは、以下の設定ディレクティブを使って実現されます:

  • 認証パスワードを設定し、インスタンスが認証されていないクライアントのリクエストを処理しないようにするために、マスターで requirepass を実行します。
  • マスターからデータを正しくレプリケートするために、レプリカがマスタで認証するために、レプリカで masterauth を実行します。

Sentinel が使われた場合、フェイルオーバ後にレプリカがマスタの役割を果たす可能性があり、古いマスタがレプリカとして機能するように再設定される可能性があるため、上記のディレクティブを全てのインスタンス、マスタとレプリカの両方で設定する必要があります。

マスタでのみデータを保護したくないため、レプリカで同じデータにアクセスできるようにするのは、通常は適切な設定です。

ただし、認証なしでアクセス可能なレプリカが必要な稀なケースでは、レプリカの優先度をゼロに設定してこのレプリカがマスタに昇格されないようにし、このレプリカで requirepass を使わずに masterauth ディレクティブのみを構成して、認証されていないクライアントがデータを読み取れるようにすることで、それを行うことができます。

Sentinel が requirepass で構成されている時に Redis サーバインスタンスに接続するには、Sentinel 構成に sentinel auth-pass ディレクティブを以下の形式で含める必要があります:

sentinel auth-pass <master-group-name> <pass>

*認証を使った Sentinel インスタンスの設定

AUTH コマンドを使ってクライアント認証を要求するように Sentinel インスタンス自体を構成することもできますが、この機能は Redis 5.0.1 以降でのみ使えます。

これを行うには、全ての Sentinel インスタンスに以下の構成ディレクティブを追加するだけです:

requirepass "your_password_here"

このように構成すると、Sentinel は以下の2つのことを行います:

  1. Sentinel にコマンドを送信するには、クライアントからパスワードが必要になります。これは、このような設定ディレクティブが Redis で一般的にどのように機能するかを示しているため、明らかです。
  2. さらに、ローカル Sentinel にアクセスするように構成された同じパスワードが、接続する他の全ての Sentinel インスタンスに対して認証するために、この Sentinel インスタンスによって使われます。

つまり、全ての Sentinel インスタンスで同じ requirepass パスワードを設定する必要があります。このようにして、全ての Sentinel は、他の全ての Sentinel にアクセスするためのパスワードを Sentinel ごとに構成する必要無しに、他の全ての Sentinel と通信できます。これは非常に非現実的です。

この設定を使う前に、クライアントライブラリが AUTH コマンドを Sentinel インスタンスに送信できることを確認してください。

*Sentinel クライアントの実装

Sentinel は、新しいマスタインスタンス(仮想 IP または他の同様のシステム)への全てのリクエストの透過的なリダイレクトを実行するようにシステムが構成されていない限り、明示的なクライアントサポートを必要とします。クライアントライブラリの実装のトピックは、ドキュメント Sentinel クライアントガイドラインで説明されています。

*より高度な概念

次のセクションでは、このドキュメントの最後の部分で説明する実装の詳細やアルゴリズムに頼ることなく、Sentinel の動作に関する幾つかの詳細を説明します。

*SDOWN および ODOWN の障害状態

Redis Sentinel には、2つの異なるダウンの概念があります。1つは主観ダウン条件(SDOWN) と呼ばれ、指定された Sentinel インスタンスにローカルなダウン条件です。もう1つは、客観的ダウン条件 (ODOWN) と呼ばれ、十分な Sentinel (少なくとも監視対象のマスタの quorum パラメータとして設定された数)に SDOWN 条件があり SENTINEL is-master-down-by-addr コマンドを使って他の Sentinel からフィードバックを得ます。

Sentinel の観点からは、is-master-down-after-milliseconds パラメータとして設定の中で指定された秒数の間、PING 要求への有効な応答を受信しない場合に SDOWN 条件に達します。

PING への受け入れ可能な応答は、以下のいずれかです:

  • PING replied with +PONG.
  • PING replied with -LOADING error.
  • PING replied with -MASTERDOWN error.

その他の応答は無効とみなされます。ただし、INFO 出力でレプリカとして自身を広告する論理マスタはダウンしていると見なされることに注意してください。

SDOWN では、設定された間隔全体で受け入れ可能な応答を受信しない必要があることに注意してください。例えば、間隔が 30000 ミリ秒 (30 秒)で、29秒ごとに受け入れ可能な ping 応答を受信した場合、インスタンスは動作していると見なされます。

SDOWN はフェイルオーバーをトリガーするのに十分ではありません: これは、単一の Sentinel が Redis インスタンスが利用できないと信じていることを意味するだけです。フェイルオーバーをトリガーするには、ODOWN 状態に到達する必要があります。

SDOWN から ODOWN に切り替えるには、強力なコンセンサスアルゴリズムは使われませんが、ゴシップの形式が使われます: 特定の Sentinel が特定の時間範囲で十分な Sentinel から動作していないという報告を受け取った場合、SDOWN が ODOWN に昇格します。この確認通知が後で欠落している場合、フラグが消されます。

フェイルオーバーを実際に開始するには、実際の過半数を使う厳密な許可が必要ですが、ODOWN 状態に到達しないと、フェイルオーバーをトリガーできません。

ODOWN 条件はマスターのみに適用されます。他の種類のインスタンスの場合、Sentinel は動作する必要が無いため、レプリカやその他の sentinel では ODOWN 状態に達することはなく、SDOWN のみになります。

ただし、SDOWN にはセマンティックな意味もあります。例えば、SDOWN 状態のレプリカは、フェイルオーバーを実行する Sentinel によって昇格されるように選択されていません。

*Sentinel と レプリカの自動検出

Sentinel は、相互に可能性を確認し、メッセージを交換するために、他の Sentinel との接続を維持します。ただし、Sentinel は同じマスタとレプリカを監視している他の Sentinel を検出するために、Redis インスタンスの Pub/Sub 機能を使うため、実行する全ての Sentinel インスタンスで他の Sentinel アドレスのリストを設定する必要はありません。

この機能は hello messages__sentinel__:hello という名前のチャンネルに送信することで実装されます。

同様に、Sentinel は Redis にクエリを実行するこのリストを自動的に検出するため、マスタにアタッチされているレプリカのリストを設定する必要はありません。

  • 全ての Sentinel は監視対象の全てのマスタとレプリカの Pub/Sub チェンネル __sentinel__:hello に、2秒ごとにメッセージを公開し、ip、ポート、runid でその存在を通知します。
  • 全ての Sentinel は、全てのマスタとレプリカの Pub/Sub チャンネル __sentinel__:hello に購読され、未知の sentinel を探します。新しい sentinel が検知されると、それらはこのマスタの sentinel として追加されます。
  • Hello メッセージには、マスタの現在の完全な構成も含まれます。受信側の sentinel に、受信したものより古い特定のマスタの構成がある場合、すぐに新しい構成に更新されます。
  • 新しい sentinel をマスタに追加する前に、sentinel は常に、同じ runid または同じアドレス (ip とポートのペア)を持つ sentinel がすでに存在するかどうかを確認します。存在する場合、全ての一致する sentinel は削除され、新しいものが追加されます。

*フェイルオーバー手順外のインスタンスの sentinel 設定

フェイルオーバーが進行中ではない場合でも、sentinel は常に監視対象インスタンスに現在の構成を設定しようとします。具体的には:

  • マスタであると主張するレプリカ(現在の構成による)は、現在のマスタでレプリケートするレプリカとして構成されます。
  • 間違ったマスタに接続されたレプリカは、正しいマスタでレプリケートするように再構成されます。

sentinel がレプリカを再構成するには、新しい構成のブロードキャストに使われる期間よりも長い間、間違った構成を観察する必要があります。

これにより、古い構成の Sentinel (例えばパーティションから再結合したばかりの Sentinel) は、更新を受信する前にレプリカ構成を変更しようとするのを防ぎます。

また、常に現在の構成を強制しようとするセマンティクスによって、フェイルオーバーがパーティションに対してより耐性があるようにすることにも注意してください:

  • フェイルオーバーしたマスターは、利用可能に戻った時にレプリカとして再構成されます。
  • パーティション中にパーティション分割されたレプリカは、到達可能になると再構成されます。

このセクションで覚えておくべき重要な教訓は以下の通りです: Sentinel は、各プロセスが常に最後の論理構成を監視対象インスタンスのセットに課そうとするシステムです

*レプリカの選択と優先度

Sentinel インスタンスがフェイルオーバーを実行する準備ができたら、マスターは ODOWN 状態にあり、Sentinel は既知の Sentinel インスタンスの大部分からフェイルオーバーの承認を受け取ったため、適切なレプリカを選択する必要があります。

レプリカの選択プロセスは、レプリカについての以下の情報で評価されます:

  1. マスタからの切断時間。
  2. レプリカポリシー。
  3. 処理されたレプリカのオフセット。
  4. 実行 ID。

構成されたマスタのタイムアウト (down-after-milliseconds option) の10倍に加えて、フェイルオーバーを実行する Sentinel の観点からマスターが使用できない時間マスターから切断されていることが判明したレプリカは、フェイルオーバーには適しないと見なされ、スキップされます。

より厳密にいえば、INFO 出力が、次の時間以上マスタから切断されていることを示唆するレプリカ:

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

信頼できないと見なされ、完全に無視されます。

レプリカの選択は、上記のテストに合格したレプリカのみが苦慮され、上記の基準に基づいて以下の順序で並べ替えられます。

  1. レプリカは、Redis インスタンスの redis.conf ファイルで構成されている replica-priority で並べ替えられます。優先度は低くなります。
  2. 優先度が同じ場合、レプリカによって処理されたレプリケーションオフセットがチェックされ、マスタからより多くのデータを受信したレプリカが選択されます。
  3. 複数のレプリカの優先度が同じで、マスタからの同じデータを処理した場合は、さらにチェックが実行され、辞書式順序で小さい実行 ID を持つレプリカが選択されます。実行 ID を低くすることは、レプリカにとって実際の利点ではありませんが、ランダムレプリカを選択するのではなく、レプリカ選択のプロセスをより決定的にするために役立ちます。

強く優先するマシンがある場合は、Redis のマスタ (フェイルオーバー後にレプリカに変わる可能性があります)とレプリカを全てreplica-priorityで設定する必要があります。それ以外の倍は、全てのインスタンスをデフォルトの実行 ID で実行できます (レプリケーションオフセットでレプリカを選択する方がはるかに興味深いため、推奨されるセットアップです)。

Redis インスタンスは、Sentinel によって新しいマスタとして選択されないため、ゼロの特別な replica-priority で設定できます。ただし、この方法で設定されたレプリカは、フェイルオーバー後に新しいマスタでレプリケートするために、Sentinel によって再構成されます。唯一の違いは、レプリカ自体がマスタになることはないということです。

*アルゴリズムと内部

以下のセクションでは、Sentinelの動作の詳細について説明します。ユーザが全ての詳細を認識する必要は厳密にはありませんが、Sentinel を深く理解することで、より効果的な方法で配備および運用できる場合があります。

*定足数

前のセクションでは、Sentinel で監視される全てのマスタが構成済みの定足数に関連付けられていることを示しました。フェイルオーバーをトリガーするために、マスタの到達不能またはエラー状態について合意する必要がある Sentinel プロセスの数を指定します。

ただし、フェイルオーバーがトリガーされた後、フェイルオーバーを実際に実行するには、少なくとも大多数の Sentinel がその Sentinel のフェイルオーバーを許可する必要があります。Sentinel は、少数の Sentinel が存在するパーティションでフェイルオーバーを時刻することはありません。

物事をもう少し明確にしようとしましょう:

  • 定足数: マスタに ODOWN のフラグを立てるためにエラー状態を検出する必要がある Sentinel プロセスの数。
  • フェイルオーバーは ODOWN 状態によってトリガーされます。
  • ただし、フェイルオーバーがトリガーされた後、フェイルオーバーしようとする Sentinel は、Sentinel の過半数 (または定足数が過半数よりも大きい数に設定されている場合は、過半数以上)への承認を要求する必要があります。

違いは微妙に見えるかもしれませんが、実際には理解して使うのは非常に簡単です。例えば、5つの Sentinel インスタンスがあり、定足数が 2 に設定されている場合は、2つ の Setinel がマスタに到達できないと判断すると、すぐにフェイルオーバーがトリガーされますが、少なくとも 3 つの Sentinel から承認される場合のみ、2つの Sentinel の1つがフェイルオーバーできます。

代わりに定足数が 5 に設定されている場合、全ての Sentinel はマスタエラー状態に合意する必要があり、フェイルオーバーするには全ての Sentinel からの承認が必要です。

これは、定足数を使って Sentinel を2つの方法で調整できることを意味します:

  1. 定足数が配備する Sentinel よりも小さい値に設定されている場合、基本的に Sentinel はマスタの障害に対してより敏感になり、少数の Sentinel でもマスターと通信できなくなるとすぐにフェイルオーバーがトリガーされます。
  2. 定足数が Sentinel の過半数より多い値に設定されている場合、マスターがダウンしていることに同意する十分に接続された Sentinel が非常に多数(過半数より多い)場合のみ、Sentinel をフェイルオーバーできるようにします。

*構成エポック

Sentinel は、幾つかの重要な理由により、フェイルオーバーを開始するために過半数からの承認を取得する必要があります:

Sentinel が承認されると、フェイルオーバーするマスターに対して一意の構成エポックを取得します。これは、フェイルオーバーの完了後に新しい構成をバージョン管理するために使われる番号です。過半数が特定のバージョンが特定の Sentinel に割り当てられていることに同意したため、他の Sentinel はそれを使えなくなります。これは、全てのフェイルオーバーの全ての構成が一意のバージョンでバージョン管理されることを意味します。これがなぜそれほど重要なのかを見ていきます。

さらに Sentinel にはルールがあります: Sentinel が特定のマスターのフェイルオーバーに別の Sentinel を投票した場合、同じマスタ―のフェイルオーバーを再試行するためにしばらく待ちます。この遅延は、sentinel.conf で設定できる failover-timeout です。これは、Sentinel が同じマスターを同時にフェイルオーバーしようとしないことを意味します。最初に承認を要求したマスタが試行し、失敗した場合はしばらくしてから別のマスターが試行します。

Redis の Sentinel は、liveness プロパティを補償します。これにより、Sentinel の大多数が通信できる場合、マスターがダウンした場合に最終的にフェイルオーバーが許可されます。

Redis の Sentinel は safety プロパティも保証します。全ての Sentinel は異なる configuration epoch を使って同じマスターをフェイルオーバーします。

*構成の伝播

Sentinel がマスターを正常にフェイルオーバーできるようになると、Sentinel は新しい構成のブロードキャストを開始し、他の Sentinel が特定のマスターに関する情報を更新します。

フェイルオーバーが成功したと見なされるには、Sentinel が選択されたレプリカに REPLICAOF NO ONE コマンドを送信でき、マスターへの切り替えが後でマスターの INFO 出力で確認される必要があります。

この時点で、レプリカの再構成が進行中の場合でも、フェイルオーバーは成功したと見なされ、全ての Sentinel が新しい構成のレポートを開始する必要があります。

新しい構成が伝播される方法が、全ての Sentinel のフェイルオーバーが異なるバージョン番号(構成エポック)で承認される理由です。

全ての Sentinel は、マスターと全てのレプリカの両方で、Redis の Pub/Sub メッセージを使ってマスターの構成のバージョンを継続的にブロードキャストします。同時に、全ての Sentinel はメッセージを待って、他の Sentinel によって広告された構成を確認します。

構成は __sentinel__:hello Pub/Sub チャンネルの中でブロードキャストされます。

全ての構成は異なるバージョン番号を持つため、大きいバージョンが小さいバージョンよりも常に優先されます。

したがって、例えば、マスターの mymaster の構成は、マスターが 192.168.1.50:6379 になると信じている全ての Sentinel から始まります。この構成には バージョン 1 があります。しばらくすると、Sentinel はバージョン 2 でフェイルオーバーすることが許可されます。フェイルオーバーが成功すると、バージョン 2 で新しい構成、例えば 192.168.1.50:9000 のブロードキャストが開始されます。新しい構成のバージョンが大きいため、他の全てのインスタンスはこの構成を確認し、それに応じて構成を更新します。

これは、Sentinel が2番目の liveness プロパティを保証することを意味します: 通信可能な Sentinel のセットは全て、より高いバージョン番号の同じ構成に収束します。

基本的に、ネットがパーティション化された場合、全てのパーティションはより高いローカル構成に収束します。パーティションが無いという特別な場合、1つのパーティションがあり、全ての Sentinel はその構成に合意します。

*パーティション下での一貫性

Redis の Sentinel の構成は結果整合性があるため、全てのパーティションは利用可能なより高い構成に収束します。ただし、Sentinel を使う実際のシステムでは、3つの異なるレイヤーがあります::

  • Redis インスタンス。
  • Sentinel インスタンス。
  • クライアント。

システムの動作を定義するには、3つ全てを考慮する必要があります。

以下は、3つのノードがあり、そえrぞれが Redis インスタンスと Sentinel インスタンスを実行している単純なネットワークです:

            +-------------+
            | Sentinel 1  |----- Client A
            | Redis 1 (M) |
            +-------------+
                    |
                    |
+-------------+     |          +------------+
| Sentinel 2  |-----+-- // ----| Sentinel 3 |----- Client B
| Redis 2 (S) |                | Redis 3 (M)|
+-------------+                +------------+

このシステムでは、元の状態では Redis 3 がマスターであり、Redis 1 と 2 がレプリカでした。古いマスターを分離するパーティションが発生しました。Sentinel 1 と 2 は、Sentinel 1 を新しいマスターとして昇格させるフェイルオーバーを開始しました。

Sentinel プロパティは、Sentinel 1 と 2 がマスターの新しい構成を持つことを保証します。Sentinel 3 は別のパーティションにあるため、古い構成のままです。

Sentinel 3 は、ネットワークパーティションが回復した時に構成が更新されることは分かっていますが、古いマスターでパーティション分割されたクライアントがある場合、パーティション中に何が起こりますか?

クライアントは、古いマスターである Redis 3 に引き続き書き込むことができます。パーティションが再結合すると、Redis 3 は Redis 1 のレプリカになり、パーティション中に書き込まれた全てのデータが失われます。

構成に応じて、このシナリオが起こるかどうかが決まります:

  • Redis をキャッシュとして使っている場合、データが失われたとしても、クライアント B が古いマスターに書き込むことができると便利です。
  • Redis をストアとして使っている場合、これは適切では無く、この問題を部分的にも防ぐためにシステムを構成する必要があります。

Redis は非同期でレプリケートされるため、このシナリオでデータ損失を完全に防ぐ方法はありませんが、以下の Redis 構成オプションを使って Redis 3 と 1 の間を相違を制限できます:

min-replicas-to-write 1
min-replicas-max-lag 10

上の設定(詳細はRedis配布物の中の自己コメントされたredis.confの例を参照してください)で、Redisインスタンスはマスターとして動作しているとき、少なくとも1つのレプリカに書き込めない場合は書き込みを受け付けなくなります。レプリケーションは非同期のため、実際に書き込みができないということは、レプリカが切断されているか、指定された max-lag 秒以上の間非同期の確認応答を送信していないことを意味します。

この構成を使うと、上記の例の Redis 3 は10秒後に使えなくなります。パーティションが回復すると、Sentinel 3 構成は新しい構成に収束し、クライアント B は有効な構成をフェッチして続行できるようになります。

一般的に、Redis + Sentinel は全体として、結果整合性のあるシステム であり、マージ機能は最後のフェイルオーバーの勝利であり、古いマスターからのデータは現在のマスターのデータをレプリケートするために破棄されます。従って確認済みの書き込みを失うウィンドウが常にあります。これは、Redis 非同期レプリケーションと、システムの "仮想" マージ機能の破棄の性質によるものです。これは、Sentinel 自体の制限では無いことに注意してください。強力に一貫性のあるレプリケートされた状態マシーンを使ってフェイルオーバーを調整する場合に、同じプロパティが適用されます。確認済みの書き込みが失われないようにする方法は以下の2つだけです:

  1. 同期リプリケーション(およびレプリケートされた状態マシーンを実行するための適切なコンセンサスアルゴリズム)を使います。
  2. 同じオブジェクトの異なるオブジェクトをマージできる結果整合性のあるシステムを使います。

Redis は現在、上記のシステムのどちらも使えず、現在は開発目標の範囲外です。ただし、SoundCloud Roshi、あるいは Netflix Dynomite などの Redis ストアの上に解決策 "2" を実装するプロキシがあります。

*Sentinel 永続状態

Sentinel 状態は、sentinel 構成ファイルに保持されます。例えば、マスタの新しい構成が受信または作成されるたびに(リーダー Sentinel)、構成は構成エポックとともにディスクに保持されます。これは、Sentinel プロセスを停止して再起動しても安全であることを意味します。

*TILT モード

Redis Sentinel は、コンピュータの時間に大きく依存します: たとえば、インスタンスが利用可能かどうかを理解するために、PING コマンドへの最後の正常な応答の時間を記憶し、それがどれくらい古いかを理解するために現在の時間と比較します。

ただし、コンピュータの時間が予期しない方法で変更された場合、あるいはコンピュータが非常にビジーな場合、あるいは何らかの理由でプロセスがブロックされた場合、Sentinel は予期しない方法で動作し始める可能性があります。

TILT モードは、システムの信頼性を低下させる可能性がある異常が検出された時に Sentinel が入ることができる、特別な"保護"モードです。Sentinel タイマー割り込みは通常1秒間に10回呼び出されるため、タイマー割り込みへの2回の呼び出しの間に、100ミリ秒程度が経過すると予想されます。

Sentinel が行うことは、前回タイマー割り込みが呼び出された時刻を登録し、それを現在の呼び出しと比較することです: 時差が負の場合、または予想外に大きい場合(2秒以上)、TTL モードに入ります(または既に入っている場合は、TILT モードの終了は延期されます)。

TILT モードの場合、Sentinel は全てを監視し続けますが:

  • 全ての行動を停止します。
  • 障害を検知する機能が信頼できなくなったため、SENTINEL is-master-down-by-addr リクエストに対して否定的に応答し始めます。

30秒間すべてが正常であるように見える場合、TILT モードは終了します。

何らかの方法で、多くのカーネルが提供する単調なクロック API を使って TILT モードを書き換えることができることに注意してください。ただし、現在のシステムでは、プロセスが中断されたばかりの場合やスケジューラによって長い間実行されなかった場合の問題が回避されるため、これが適切な解決策であるかどうかはまだ明らかではありません。

このマニュアルのページで使われているスレーブという語についての注意: Redis 5 から下位互換性のためではない場合に、Redisプロジェクトはスレーブという語をもう使わなくなりました。残念ながらこのコマンドではスレーブという単語はプロトコルの一部です。ですので、このAPIが自然に廃止される時に限り、そのような出現を削除することができます。

TOP
inserted by FC2 system