ZooKeeperは、オープンソースの分散調整サービスおよび分散データ整合性ソリューションです。ZooKeeperに基づいて、ネーミングサービス、クラスター管理、マスター選択、分散ロックなどの機能を実現できます。
高可用性
ZooKeeperの可用性を確保するために、本番環境ではZooKeeperクラスターモードを使用して外部サービスを提供し、クラスターサイズは少なくとも3つのZooKeeperノードで構成されます。
クラスタは少なくとも3つのノードで構成されています
実際、ZooKeeper 2ノードはクラスターを形成して外部サービスを提供することもできますが、クラスターを使用する主な目的は高可用性です。2つのノードがクラスターを形成する場合、ノードの1つがダウンし、ZooKeeperノードは外部サービスを正常に提供できません。したがって、クラスターの意味は失われます。
3つのノードがクラスターを形成し、いずれかのノードがハングアップした場合、ZooKeeperのリーダー選出メカニズムに従って、他の2つのノードの1つをリーダーとして選択でき、クラスターは引き続き外部にサービスを提供できます。
ノードが多いほど良いとは限りません
- ノードが多いほど、より多くのリソースが使用されます
- ノードが多いほど、ZooKeeperノード間の通信コストが高くなり、ノード間で相互接続されるソケットが多くなります。ZooKeeperクラスターのトランザクション処理に影響します
- ノードが多いほど、スプリットブレインの可能性が高くなります
クラスターサイズが奇数
独自のコストとリソースを検討することに加えて、クラスターサイズもZooKeeperの機能と併せて検討する必要があります。
- リソースを節約する
- 3ノードクラスターと4ノードクラスターの場合は、3ノードクラスターの使用を選択し、5ノードクラスターと6ノードクラスターの場合は、5ノードクラスターの使用を選択します。等々。実稼働環境で高可用性を確保するために、3ノードクラスターは最大1つまでハングすることができ、4ノードクラスターは最大1つまでハングすることができます(理由は半分以上の原則で説明されています)。同様に、5ノードのクラスターでは最大2ユニット、6ノードのクラスターでは最大2ユニットを使用できます。
- リソースを節約するために、奇数ノードを使用して同じ高可用性を実現する必要があります。
- クラスターの可用性
- クラスター内のノード間のネットワーク通信に問題がある場合の奇数と偶数のクラスターへの影響
クラスター構成
ZooKeeperクラスター構成には、少なくとも2つの変更が必要です。
1.クラスター構成を増やす
クラスターの構成を{ZK_HOME} /conf/zoo.cfgに追加します。構造はserver.id = ip:port1:port2に基づいています。
たとえば、次の構成ファイルは3つのZooKeeperで構成されるクラスターを表しています。
server.1 = localhost:2881:3881 server.2 = localhost:2882:3882server.3 = localhost:2883:3883
2.ノードIDを構成する
zoo.cfgでクラスターを構成するときは、server.idを指定する必要があります。このIDは、(zoo.cfgで構成された)dataDirで指定されたディレクトリにmyidファイルを作成する必要があります。ファイルのコンテンツは、現在のZooKeeperノードのIDです。
クラスターの役割
ZooKeeperはマスター/スレーブの概念を使用しませんが、クラスター内のノードを3つのタイプの役割に分割します。
- 盟主
- ZooKeeperクラスターでは、リーダーは1つしか存在できません。このリーダーは、クラスター内のトランザクション要求の唯一のスケジューラーおよびプロセッサーです。いわゆるトランザクション要求は、クラスターの状態を変更する要求を指します。リーダーは、トランザクションIDに基づいてトランザクション処理の順序を確認できます。 。
- クラスタ内に複数のリーダーがいる場合、この現象は「スプリットブレイン」と呼ばれます。クラスター内の複数のリーダーの影響を想像してみてください。
- これは元の大きなクラスターと同等であり、複数の小さなクラスターが分割され、それらの間のデータは互いに同期されません。クラスタ内のデータは、「スプリットブレイン」の後で非常に乱雑になります。
- フォロワー
- FollowerロールのZooKeeperサービスは、非トランザクションリクエストのみを処理できます。クライアントトランザクションリクエストを受信すると、リクエストをリーダーサーバーに転送し、リーダー選挙に参加し、リーダートランザクション処理投票に参加します。
- フォロワーは、クラスター内のリーダーが使用できないことを検出すると、その状態を変更し、リーダー選挙投票を開始します。最終的に、クラスター内のフォロワーがリーダーとして選択されます。
- 観察者
- オブザーバーはフォロワーに非常によく似ており、非トランザクション要求を処理でき、トランザクション要求をリーダーサーバーに転送します。
- フォロワーとは異なり、オブザーバーはリーダー選挙には参加せず、リーダートランザクション投票には参加しません。
- オブザーバーは、クラスターのトランザクション処理機能に影響を与えることなく、クラスターの非トランザクション処理機能を改善するために使用されます。
リーダー選挙
リーダーはクラスター内で非常に重要な役割であり、トランザクション全体の処理とスケジューリングを担当し、分散データの一貫性を確保するための鍵となります。リーダーはZooKeeperクラスターで非常に重要であるため、クラスターに常に1つのリーダーのみが存在することを確認する必要があります。
クラスター内のリーダーが利用できない場合は、クラスターから最適なサービスを見つけてリーダーに昇格させ、トランザクションの処理と責任のスケジュールを継続できるようにするメカニズムが必要です。このプロセスはリーダー選挙と呼ばれます。
選挙メカニズム
ZooKeeper選挙指導者は、次の原則に依存し、優先順位に従います。
1.選挙投票は同じラウンドで行われなければならない
フォロワーサービスの選挙ラウンドが異なる場合、投票は採用されません。
2.最新のデータを持つノードが最初にリーダーになります
新旧のデータはトランザクションIDによって決まります。トランザクションIDが大きいほど、ノードデータはリーダーのデータに近いと見なされ、自然にリーダーになるはずです。
3. server.idを比較します。より高いid値を持つものが最初にリーダーになります
各参加ノードのトランザクションIDが同じ場合は、server.idを使用して比較します。server.idは、クラスター内のノードの一意のIDであり、myidファイルで構成されます。
クラスターの起動時にリーダーが選出されるか、クラスターの実行中にリーダーが再選されるかは関係ありません。クラスタ内の各フォロワーロールサービスは、上記の条件に基づいて適切なリーダーを選択します。ノードの半分以上が選択されると、ノードはリーダーに昇格します。
半分以上の原則
ZooKeeperクラスターには多くのタイプの投票があります。リーダー選挙投票、事業提案投票、これらの投票は多数決の原則に依存しています。言い換えると、ZooKeeperは、投票結果がクラスターの総数の半分を超えており、後続のトランザクションを安全に処理できると考えています。
- 事業提案票
- ZooKeeperクラスターを形成する3つのノードがあり、クライアントがノードの追加を要求するとします。トランザクション要求を受け取った後、リーダーはすべてのフォロワーが投票するための「ノード作成」提案を開始します。リーダーがクラスターからフィードバックの半分以上を受け取った場合、リーダーは引き続きすべてのフォロワーへのコミットを開始します。現時点では、リーダーはクラスターが半分以上であると考えています。クラスターがハングアップしても、安全で信頼できます。
- リーダー選挙投票
- ZooKeeperクラスターを形成するノードが3つあるとします。現時点では、リーダーが電話を切り、リーダーに投票する必要があります。同じ投票結果が半分以上の場合、リーダーが選出されます。
- 利用可能なノードをクラスター化する
- ZooKeeperクラスターの各ノードには独自の役割があり、クラスターの可用性を実現するには、半分以上の原則を満たす必要があります。この半分を超えると、利用可能なリーダーロール+フォロワーロールの数が、クラスター内のリーダーロール+フォロワーロールの総数よりも多くなります。
- ZooKeeperクラスターを形成する5つのノード、1つのリーダー、2つのフォロワー、2つのオブザーバーがあるとします。2人のフォロワー、または1人のリーダーと1人のフォロワーが停止している場合、クラスターは使用できなくなります。オブザーバーの役割は、いかなる形の投票にも参加しないからです。
いわゆる半分以上の原理アルゴリズムは、投票数>クラスタ内のノードの総数/ 2です。クラスタノードの総数/ 2の計算結果は切り捨てられます。
このアルゴリズムは、ZooKeeperのソースコードQuorumMaj.javaに実装されています。以下のコードスニペットが削減されました。
public boolean containsQuorum(HashSet <Long> set){ / ** nはクラスターの総数を参照します* / int half = n / 2; return(set.size()> half);}
振り返って、奇数クラスタと偶数クラスタのリーダー選挙の結果を見てみましょう。
したがって、3つのノードと4つのノードで構成されるクラスターは、ZooKeeperの原則の下で最大で1つのノードしか持つことができませんが、4〜3つは1つのノードリソースを浪費します。
シーン戦闘
2つのシナリオを使用して、クラスターが使用できない場合のリーダー再選プロセスを理解します。
3ノードクラスター再選リーダー
server.1(フォロワー)、server.2(リーダー)、server.3(フォロワー)の3つのノードで構成されるクラスターを想定します。現在、server.2は使用できません。クラスターには次の変更があります。
1.クラスターが利用できない
リーダーがダウンしているため、クラスターはトランザクション要求に使用できません。
2.ステータス変更
すべてのフォロワーノードは、ステータスをLOOKINGに変更し、独自の投票を変更します。投票内容は、自分のノードのトランザクションIDとserver.idです。(トランザクションID、server.id)で表します。
server.1のトランザクションIDが10であるとすると、変更の独自の投票は(10、1)であり、server.3のトランザクションIDは8であり、変更の独自の投票は(8、3)です。
3.最初の投票
変更の投票をクラスター内のすべてのフォロワーノードに送信します。server.1は、それ自体を含め、クラスター内のすべてのフォロワーに(10、1)を送信します。Server.3は同じで、すべてのフォロワーに(8、3)を送信します。
したがって、server.1は2つの票(10、1)と(8、3)を受け取り、server.3は2つの票(8、3)と(10、1)を受け取ります。
4. PKの投票
投票の開始に加えて、各フォロワーノードは他のフォロワーから送信された投票も受け取り、2つの提案されたトランザクションIDとserver.idを独自の投票PKと比較します。PKの結果は、状態を変更して再度投票するかどうかを決定します。
server.1の場合、2つの投票(10、1)と(8、3)が受信されます。それ自体が変更した投票と比較すると、どちらも自分の投票(10、1)より大きくないため、server.1はそれ自体を維持します投票は変更されません。
server.3の場合、2つの票(10、1)と(8、3)を受け取ります。自身の変更の票と比較した後、server.1によって送信された票は自分の票より大きいため、server.3は自分の投票を変更し、変更した投票をクラスター内のすべてのフォロワーに送信します。
5. 2回目の投票
server.3は投票を(10、1)に変更し、クラスター内のすべてのフォロワーに再度投票を送信します。
server.1の場合、2番目のラウンドで(10、1)の投票が受信され、server.1はPK後も変更されないままです。
server.3では、server.3自体が(10、3)投票に変更されたため、今回は(10、1)投票が受信されました。
この時点で、server.1とserver.3は投票について合意に達しました。
6.投票受付バケット
ノードが受信した投票は受信バケットに格納され、各フォロワーの投票結果はバケットに1回だけ記録されます。ZooKeeperソースコードの受信バケットは、Mapによって実装されます。
次のコードスニペットは、ZooKeeperによって定義され、バケットにデータを書き込む受信バケットです。Map.KeyはLong型で、投票元ノードのserver.idを格納するために使用され、Voteは対応するノードの投票情報です。ノードは投票を受信した後、受信バケットを更新します。つまり、バケットはすべてのフォロワーノードの投票を保存し、最後の投票結果のみが保存されます。
HashMap <ロング、投票> recvset = new HashMap <ロング、投票>(); recvset.put(n.sid、new Vote(n.leader、n.zxid、n.electionEpoch、n.peerEpoch));
7.統計投票
投票を受け取った後、毎回投票を数えようと試み、投票数の半分が過ぎると選挙は成功します。
投票統計のデータは、投票受信バケット内の投票データから取得されます。このシナリオを最初から説明し、受信バケット内のデータの変化を見てみましょう。
server.2が電話を切った後、server.1とserver.3が最初の投票を開始します。
server.1は、server.1から(10、1)投票を受け取り、server.3から(8、3)投票を受け取ります。
server.3は、server.1から(10、1)票を、server.3から(8、3)票も受け取ります。このとき、server.1とserver.3の受信バケット内のデータは次のようになります。
server.3がPKに合格した後、server.1の投票が自身の投票よりも大きいと信じたため、server.3は投票を変更し、投票を再開しました。
server.1はserver.3から(10、1)の投票を受け取り、server.3はserver.3から(10、1)の投票を受け取りました。このとき、server.1とserver.3の受信バケット内のデータは次のようになります。
ZooKeeperの原則の半分以上に基づいて:バケットに投票してserver.1をリーダーとして2回選出し、半分以上を2> 3/2、つまり2> 1に選出してください。
最後に、sever.1ノードがLeaderに昇格し、server.3がFollowerに変更されました。
クラスター拡張リーダーをいつ開始するか
ZooKeeperクラスターを拡張するには、zoo.cfg構成ファイルに新しいノードを追加する必要があります。拡張プロセスはZooKeeper拡張で導入されました。ここでは、3ノードの容量が5ノードに拡張された場合のリーダー起動のタイミングについて説明します。
現在、クラスターを形成している3つのノード、つまりserver.1(フォロワー)、server.2(リーダー)、およびserver.3(フォロワー)があると想定します。クラスター内のノードトランザクションIDは同じであると想定します。設定ファイルは以下の通りです。
server.1 = localhost:2881:3881 server.2 = localhost:2882:3882server.3 = localhost:2883:3883
1.新しいノードがクラスターに参加します
2つの新しいノード、server.4とserver.5がクラスターに追加されます。最初に、server.4とserver.5のzoo.cfg構成を変更して開始します。ノード4および5は、起動後に投票ステータスを変更し、リーダー選挙投票のラウンドを開始します。server.1、server.2、およびserver.3が投票を受け取った後、リーダーがクラスターで選択されているため、server.4およびserver.5の投票結果を直接フィードバックします。server.2がリーダーです。投票を受けたserver.4とserver.5は、半分以上の原則に基づいてserver.2がリーダーであると判断し、フォロワーに切り替えます。
#节点server.1、server.2、server.3配置 サーバー.1 = localhost:2881:3881server.2 = localhost:2882:3882server.3 = localhost:2883:3883#节点サーバー.4、server.5配置サーバー.1 = localhost:2881:3881server.2 = localhost:2882:3882server.3 = localhost:2883:3883server.4 = localhost:2884:3884server.5 = localhost:2885:3885
2.リーダーを停止
server.4とserver.5を追加すると、クラスターserver.1、server.2、およびserver.3のzoo.cfg構成を変更して再起動する必要があります。ただし、リーダーノードを再起動すると、リーダーの再起動によってクラスターのフォロワーがリーダーの再選を開始するため、注意することが重要です。server.4とserver.5の2つの新しいノードが正常に追加された後、新しいノードが追加されるため、クラスターはリーダーを変更しません。したがって、現在server.2は引き続きリーダーです。
クラスターがどうなるかを確認するために、間違った順序で開始しました。server.2zoo.cfg構成ファイルを変更し、server.4およびserver.5の構成を増やして、server.2サービスを停止します。server.2が停止すると、リーダーは存在しなくなり、クラスター内のすべてのフォロワーが投票を開始します。server.1とserver.3が投票を開始するとき、server.4とserver.5ノードはserver.1とserver.3のクラスター構成に含まれていないため、投票はserver.4とserver.5に送信されません。対照的に、server.4およびserver.5は、クラスター内のすべてのノードに投票を送信します。つまり、server.1とserver.3の場合、クラスターにはノードが3つしかないと考えています。server.4とserver.5については、クラスター内に5つのノードがあると考えています。
半分以上の原則に従って、server.1とserver.3はすぐに新しいリーダーを選択します。ここでは、server.3が新しいリーダーになるように昇格されたと仮定します。しかし、server.2を起動しなかった場合、投票は半分以上の原則を満たしていないため、server.4とserver.5は常にLeaderに投票します。これまでは、クラスター内のノードのステータスは次のようになっています。
3.リーダーを開始
次に、server.2を起動します。server.2zoo.cfgはすでにserver.1からserverv.5への完全な構成であるため、選挙投票はserver.2の起動後に開始され、serverv.4およびserverv.5も常に選挙投票を開始します。server.2の選挙ラウンドがserverv.4とserverv.5の選挙ラウンドと調整されると、最後にserver.2はその状態を変更し、server.5がLeadaderであると判断します。
予期しないことが起こり、2人のリーダーが現れました。
ZooKeeperクラスターが拡張されている場合、リーダーノードが最後に起動されると、リーダーノードが再起動する前にすべてのフォロワーノードのzoo.cfg構成が同じであり、相互接続する同じクラスター構成に基づいているため、この問題は回避でき、投票します選挙。