tl;dr
Zookeeper、Consul、または etcd などのレジストリのいずれかを使用してマスター選出を実装した場合でも、古いマスターがそれがもはやマスターではないことを認識せず、書き込みを試みる競合状態が常に存在するようです。書き込みのブロックが解除され、サービスの 2 つのインスタンスが同時に書き込みを行うことになりますが、これは避けたいと考えています。この競合状態なしでマスター選出を実装するにはどうすればよいでしょうか?
詳細な問題の説明
Zookeeper、Consul、etcd などのレジストリのいずれかを使用して、フェイルオーバー用のマスター選出を実装するとします。
サービス S1、S2、S3 の 3 つのインスタンスがあり、それぞれが同じマシン上に対応するレジストリ ノードを持ち、現在 S1 がマスターで、S2 と S3 がスレーブであるとします。
さらに、S1、S2、S3 はすべて共有状態をレジストリに保存しますが、同時アクセスによって状態が矛盾する可能性があるため、複数のインスタンスが同時にその状態を書き込むことは望ましくありません。
S1 が、レジストリに格納されている共有状態への書き込み操作の最中であるとします。つまり、リーダーであるかどうかを再度確認する前に、さらに書き込み操作を実行します。
この時点でネットワーク パーティションがあるとします。1 つのパーティションは S1 です。もう一方のパーティションは S2 と S3 であるため、クォーラムがあります。
レジストリは、S2 を新しいリーダーとして正しく識別し、S1 をリーダーとして無効にします。
S2 は新しいリーダーであるためアクティブになり、レジストリに格納されている共有状態への一連の書き込み操作を開始します。
パーティションが修復されます。
この時点で、S1 と S2 の両方が同時にレジストリへの書き込み操作を実行し、パーティションが修復されるため両方の書き込み操作が成功し、一貫性のない状態になる可能性があります。
サンプル トレースは次のとおりです。
- S1 はマスターであることを通知され、レジストリの共有状態への書き込み操作を開始します
- パーティションが発生し、S1 が一方のパーティションに、S2 と S3 が他方のパーティションに
- S2 は新しいマスターとして識別されます
- S2 は新しいマスターであることが通知され、レジストリの共有状態への書き込み操作を開始します
- パーティションが修復されました
- S1 はレジストリの共有状態に書き込み、パーティションがないため成功します
- S2 はレジストリの共有状態に書き込み、これも成功するため、S1 との書き込みが任意にインターリーブされます。
- S1 はマスターではなくなったことを通知され、書き込みを停止します
考え
- Consul のセッションの観点から考えると、セッション ID も取り、そのセッション ID がまだマスターのものである場合にのみ成功する API 書き込み呼び出しは、この問題を解決しますか?
- Consul または他のレジストリにそのような呼び出しはありますか?