Zookeeperの選挙メカニズム
9662 ワード
Zookeeperの選挙メカニズム
#zookeeperクラスタ
複数のインスタンスを構成して、1つのクラスタが水平拡張の目的を達成するために対外的にサービスを提供するように構成され、各サーバのデータは同じであり、各サーバは対外的に読み取りと書き込みのサービスを提供することができる.これはredisと同じであり、すなわちクライアントにとって各サービスは平等である.
この記事は主にリーダーの選択メカニズムを分析し、zookeeperは3つの方法を提供しています.
LeaderElection AuthFastLeaderElection FastLeaderElectionのデフォルトのアルゴリズムはFastLeaderElectionなので、この主な分析はその選挙メカニズムです.
選択メカニズムにおけるコンセプトサーバIDは,例えば3台のサーバがあり,番号はそれぞれ1,2,3である.
番号が大きいほど、選択アルゴリズムの重みが大きくなります.
データIDサーバに格納最大データID.
値が大きいほど、データが新しいほど、選挙アルゴリズムでデータが新しいほど重みが大きくなります.
論理クロックまたは投票回数と呼ばれ、同じ投票過程における論理クロック値は同じである.投票が終わるごとにこのデータが増加し、受信した他のサーバが返す投票情報の数値と比較して、異なる値に基づいて異なる判断を下す.
選挙状態LOOKING、選挙状態.FOLLOWING、従者状態、リーダー状態を同期し、投票に参加します.OBSERVING、状態を観察し、リーダー状態を同期し、投票に参加しない.リーダー状態.選挙メッセージの内容は、投票が完了すると、以下の内容を含むクラスタ内のすべてのサーバに投票情報を送信する必要があります.
サーバIDデータID論理クロック選択状態選択フローチャートは、各サーバが独立しているため、起動時に初期状態から選挙に参加し、以下に簡易フローチャートを示す.
選挙状態図は、すべてのインスタンスにデータがないと仮定し、サーバの起動順序がA,B,Cであると仮定したLeader選択中の状態変化を示す.
ソース分析QuorumPeerは主にこのクラスを見て、LOOKING状態だけが選挙アルゴリズムを実行します.各サーバは起動時に自分をリーダーとして選択し、投票情報を送信し、リーダーが選出されるまでループします.
すでに勝ったかどうかを判断するのは、投票数が半数を超えると勝つ論理だ.
#選挙プロセスの簡単な説明現在5台のサーバーがあり、各サーバーにはデータがなく、それらの番号はそれぞれ1,2,3,4,5で、番号によって順次起動し、それらの選択過程は以下の通りである.
サーバ1が起動し、自分に投票してから投票情報を送信し、他の機器が起動していないためフィードバック情報が受信されず、サーバ1の状態はずっとLookingに属している.サーバ2が起動して自分に投票するとともに、直前に起動したサーバ1と交換した結果、サーバ2の番号が大きいためサーバ2が勝ったが、この時点で投票数が半数を超えていないため、両サーバの状態は依然としてLOOKINGである.サーバ3が起動し、自分に投票するとともに、以前に起動したサーバ1,2と情報を交換し、サーバ3の番号が最大であるためサーバ3が勝利し、このとき投票数がちょうど半数を超えるため、サーバ3がリーダーとなり、サーバ1,2が末っ子となる.サーバ4が起動して自分に投票し、同時に前に起動したサーバ1,2,3と情報を交換し、サーバ4の番号が大きいにもかかわらず、前のサーバ3が勝っているので、サーバ4は末っ子になるしかない.サーバ5が起動し、後の論理はサーバ4と弟となる.
#zookeeperクラスタ
複数のインスタンスを構成して、1つのクラスタが水平拡張の目的を達成するために対外的にサービスを提供するように構成され、各サーバのデータは同じであり、各サーバは対外的に読み取りと書き込みのサービスを提供することができる.これはredisと同じであり、すなわちクライアントにとって各サービスは平等である.
この記事は主にリーダーの選択メカニズムを分析し、zookeeperは3つの方法を提供しています.
LeaderElection AuthFastLeaderElection FastLeaderElectionのデフォルトのアルゴリズムはFastLeaderElectionなので、この主な分析はその選挙メカニズムです.
選択メカニズムにおけるコンセプトサーバIDは,例えば3台のサーバがあり,番号はそれぞれ1,2,3である.
番号が大きいほど、選択アルゴリズムの重みが大きくなります.
データIDサーバに格納最大データID.
値が大きいほど、データが新しいほど、選挙アルゴリズムでデータが新しいほど重みが大きくなります.
論理クロックまたは投票回数と呼ばれ、同じ投票過程における論理クロック値は同じである.投票が終わるごとにこのデータが増加し、受信した他のサーバが返す投票情報の数値と比較して、異なる値に基づいて異なる判断を下す.
選挙状態LOOKING、選挙状態.FOLLOWING、従者状態、リーダー状態を同期し、投票に参加します.OBSERVING、状態を観察し、リーダー状態を同期し、投票に参加しない.リーダー状態.選挙メッセージの内容は、投票が完了すると、以下の内容を含むクラスタ内のすべてのサーバに投票情報を送信する必要があります.
サーバIDデータID論理クロック選択状態選択フローチャートは、各サーバが独立しているため、起動時に初期状態から選挙に参加し、以下に簡易フローチャートを示す.
選挙状態図は、すべてのインスタンスにデータがないと仮定し、サーバの起動順序がA,B,Cであると仮定したLeader選択中の状態変化を示す.
ソース分析QuorumPeerは主にこのクラスを見て、LOOKING状態だけが選挙アルゴリズムを実行します.各サーバは起動時に自分をリーダーとして選択し、投票情報を送信し、リーダーが選出されるまでループします.
public void run() {
//.......
try {
while (running) {
switch (getPeerState()) {
case LOOKING:
if (Boolean.getBoolean("readonlymode.enabled")) {
//...
try {
// ...
setCurrentVote(makeLEStrategy().lookForLeader());
} catch (Exception e) {
//...
} finally {
//...
}
} else {
try {
//...
setCurrentVote(makeLEStrategy().lookForLeader());
} catch (Exception e) {
//...
}
}
break;
case OBSERVING:
//...
break;
case FOLLOWING:
//...
break;
case LEADING:
//...
break;
}
}
} finally {
//...
}
}
FastLeaderElection
zookeeper , : 。
public Vote lookForLeader() throws InterruptedException {
//...
try {
HashMap recvset = new HashMap();
HashMap outofelection = new HashMap();
int notTimeout = finalizeWait;
synchronized(this){
//
logicalclock.incrementAndGet();
updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());
}
//
sendNotifications();
// ,
while ((self.getPeerState() == ServerState.LOOKING) &&
(!stop)){
Notification n = recvqueue.poll(notTimeout,
TimeUnit.MILLISECONDS);
//
if(n == null){
if(manager.haveDelivered()){
sendNotifications();
} else {
manager.connectAll();
}
//...
}
//
else if (self.getCurrentAndNextConfigVoters().contains(n.sid)) {
switch (n.state) {
case LOOKING:
// ,
if (n.electionEpoch > logicalclock.get()) {
logicalclock.set(n.electionEpoch);
recvset.clear();
//
if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
getInitId(), getInitLastLoggedZxid(), getPeerEpoch())) {
updateProposal(n.leader, n.zxid, n.peerEpoch);
} else {
updateProposal(getInitId(),
getInitLastLoggedZxid(),
getPeerEpoch());
}
//
sendNotifications();
} else if (n.electionEpoch < logicalclock.get()) {
//
break;
} else if (totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
proposedLeader, proposedZxid, proposedEpoch)) {
//
updateProposal(n.leader, n.zxid, n.peerEpoch);
sendNotifications();
}
recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));
//
if (termPredicate(recvset,
new Vote(proposedLeader, proposedZxid,
logicalclock.get(), proposedEpoch))) {
// Verify if there is any change in the proposed leader
while((n = recvqueue.poll(finalizeWait,
TimeUnit.MILLISECONDS)) != null){
if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
proposedLeader, proposedZxid, proposedEpoch)){
recvqueue.put(n);
break;
}
}
if (n == null) {
self.setPeerState((proposedLeader == self.getId()) ?
ServerState.LEADING: learningState());
Vote endVote = new Vote(proposedLeader,
proposedZxid, proposedEpoch);
leaveInstance(endVote);
return endVote;
}
}
break;
case OBSERVING:
//
break;
case FOLLOWING:
case LEADING:
//
if(n.electionEpoch == logicalclock.get()){
recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));
//
if(termPredicate(recvset, new Vote(n.leader,
n.zxid, n.electionEpoch, n.peerEpoch, n.state))
&& checkLeader(outofelection, n.leader, n.electionEpoch)) {
self.setPeerState((n.leader == self.getId()) ?
ServerState.LEADING: learningState());
Vote endVote = new Vote(n.leader, n.zxid, n.peerEpoch);
leaveInstance(endVote);
return endVote;
}
}
//
outofelection.put(n.sid, new Vote(n.leader,
IGNOREVALUE, IGNOREVALUE, n.peerEpoch, n.state));
if (termPredicate(outofelection, new Vote(n.leader,
IGNOREVALUE, IGNOREVALUE, n.peerEpoch, n.state))
&& checkLeader(outofelection, n.leader, IGNOREVALUE)) {
synchronized(this){
logicalclock.set(n.electionEpoch);
self.setPeerState((n.leader == self.getId()) ?
ServerState.LEADING: learningState());
}
Vote endVote = new Vote(n.leader, n.zxid, n.peerEpoch);
leaveInstance(endVote);
return endVote;
}
break;
default:
//
break;
}
} else {
LOG.warn("Ignoring notification from non-cluster member " + n.sid);
}
}
return null;
} finally {
//...
}
}
すでに勝ったかどうかを判断するのは、投票数が半数を超えると勝つ論理だ.
#選挙プロセスの簡単な説明現在5台のサーバーがあり、各サーバーにはデータがなく、それらの番号はそれぞれ1,2,3,4,5で、番号によって順次起動し、それらの選択過程は以下の通りである.
サーバ1が起動し、自分に投票してから投票情報を送信し、他の機器が起動していないためフィードバック情報が受信されず、サーバ1の状態はずっとLookingに属している.サーバ2が起動して自分に投票するとともに、直前に起動したサーバ1と交換した結果、サーバ2の番号が大きいためサーバ2が勝ったが、この時点で投票数が半数を超えていないため、両サーバの状態は依然としてLOOKINGである.サーバ3が起動し、自分に投票するとともに、以前に起動したサーバ1,2と情報を交換し、サーバ3の番号が最大であるためサーバ3が勝利し、このとき投票数がちょうど半数を超えるため、サーバ3がリーダーとなり、サーバ1,2が末っ子となる.サーバ4が起動して自分に投票し、同時に前に起動したサーバ1,2,3と情報を交換し、サーバ4の番号が大きいにもかかわらず、前のサーバ3が勝っているので、サーバ4は末っ子になるしかない.サーバ5が起動し、後の論理はサーバ4と弟となる.