個別のノードがダウンすること自体は防ぎようがない。よって個別のダウンが発生してもシステムが稼働し続けることを目指すのが健全である。言い換えると、ノードが不足する状況が発生したときにどれだけその影響を小さく止められるか、を対策するのである。
リードレプリカがダウンしたとき
リードレプリカがダウンし、一定時間後に再起動したとする。このレプリカがただちに読み取りリクエストの処理を再開してしまうと、古いデータをレスポンスしてしまいかねない。よってこのときの復旧手順としては、まずはリードレプリカの状態をリーダーノードに追いつかせることが最優先となる。
通常時のリードレプリカはリーダーからのレプリケーションログを絶え間なく受け取り続けている。つまり、ダウンから復旧したリードレプリカは、「ダウンした時点でどこまで処理済みだったか」を覚えている。復旧した時点で、ダウン期間のレプリケーションログをリーダーにリクエストし、キャッチアップすれば再稼働できる。
リードレプリカが再起不能のときは、ノードをクラスタから切り離して新しいリードレプリカを追加しよう。この時の手順は前項にて述べた。
リーダーがダウンしたとき
フェイルオーバーを実施しよう。フェイルオーバーとは、リーダーがダウンしたときの一連の手続きを総合した呼び名である。おおよそ総括すると次のような手順が含まれる。
- リードレプリカのうち1台をリーダーノードに昇格させる
- クライアントが新しいリーダーに書き込みリクエストを送信するように設定を更新する
- 残りのリードレプリカが新しいリーダーからレプリケーションを取得するよう設定を更新する
ここではフェイルオーバーを自動で実施するか、手動で実施するかというトレードオフが存在する。体系化された自動フェイルオーバーの設定事項は存在するが、配慮すべき障害点が多いことを踏まえると、フェイルオーバーの意思決定を自動化しないという選択肢も十分妥当である。例えば GitHub は自動フェイルオーバーの事故を踏まえて手動フェイルオーバーに切り替えている1。
そのうえで、自動フェイルオーバーは次のような流れで実施される。
リーダーがダウンしたことを検知する。
タイムアウトによって検出するのが一般的である。例えば30秒間疎通が確認できなければダウンしているとみなすなどと設定する。閾値の設定はプロジェクトによって異なるので、実際の運用ケースから経験主義的に導き出す必要がある。ただしネットワーク全体が遅延しているようなケースでは、閾値が低ければ低いほどフェイルオーバーが連鎖して暴走し、システム全体の負荷上昇に歯止めが効かなくなることも考えられる。十分な注意を払う必要があるし、最終的には人が介入して緊急脱出できるような仕組みも結局は必要になるだろう。
新しいリーダーを選出する
コンセンサスアルゴリズムによって決定されることもあるし、コントローラノードをあらかじめ用意しておいて意思決定を託すこともあるだろう。非同期レプリケーションが行われていた場合には、原則として、元リーダーのデータをもっとも最新分まで取得できていたレプリカが新しいリーダーとなるのが理想である。
新しいリーダーを利用するようにシステムを再設定する
クライアントが新しいリーダーに書き込みリクエストを送信するようにする。リードレプリカは新しいリーダーからレプリケーションログを取得するようにする。ダウンした旧リーダーノードがクラスタに復帰した場合には、もはやそれがリーダーでないと教えてレプリカに格下げする必要もある。リーダーノードがふたつ以上存在してしまうようになると、データの整合性は保証不能になる。