solrCloud选举leader的逻辑分析
First call *setup(ElectionContext) to ensure the election process is in it'd.
Next calljoinElection(ElectionContext) to start the leader election.
The implementation follows the classic ZooKeeper recipe of creating an ephemeral, sequential node for each candidate and then looking at the set of such nodes -
if the created node is the lowest sequential node, the candidate that created the node is the leader.
If not, the candidate puts a watch on the next lowest node it finds, and if that node goes down, starts the whole process over by checking if it's the lowest sequential node, etc.
org.apache.solr.cloud.LeaderElector实现选举leader的逻辑。
首先调用setup方法保证选举初始化,主要是保证写在zookeeper上的信息节点存在。
[java]
/**
* Set up any ZooKeeper nodes needed for leader election.
*/
public void setup(final ElectionContext context) throws InterruptedException,
KeeperException {
String electZKPath = context.electionPath + LeaderElector.ELECTION_NODE;
zkCmdExecutor.ensureExists(electZKPath, zkClient);
}
加入选举队列实现
每个shard进入集群后,会在zookeeper上注册一个序列号类似,n_0000000001 or n_0000000003
应该是以active的状态记录,每次进入选举的队列里,都会先取得新的序列号,先进序列号越小,这个序列号对于选举leader很重要,每次选举leader会从最小的序列号做为leader,初次创建的时候,就会作为首选 的leader。
至于每次有leader发生故障的时候,看检查自己是不是最小的那个序列号,如果是,则可以做一下leader的初始化工作,如果不是,至以当前第二小的做为新的leader看齐。
挂掉的leader的shard再成功起来的时候,照道理应该是改为最大的序列号,变为followe者。
加入选举队列实现主要代码 :(返回选举后的leader序列号)
[java]
public int joinElection(ElectionContext context) throws KeeperException, InterruptedException, IOException {
final String shardsElectZkPath = context.electionPath + LeaderElector.ELECTION_NODE;
long sessionId = zkClient.getSolrZooKeeper().getSessionId();
String id = sessionId + "-" + context.id;
String leaderSeqPath = null;
boolean cont = true;
int tries = 0;
while (cont) {
try {
//取出shard片对应的leader seq信息。
leaderSeqPath = zkClient.create(shardsElectZkPath + "/" + id + "-n_", null,
CreateMode.EPHEMERAL_SEQUENTIAL, false);
context.leaderSeqPath = leaderSeqPath;
cont = false;
} catch (ConnectionLossException e) {
// we don't know if we made our node or not...
List<String> entries = zkClient.getChildren(shardsElectZkPath, null, true);
//检查自己是否在这个选 举的队列里
boolean foundId = false;
for (String entry : entries) {
String nodeId = getNodeId(entry);
if (id.equals(nodeId)) {
// we did create our node...
foundId = true;
break;
}
}
//没找到则跳出微循环,如果重试已超过20次则抛出异常
if (!foundId) {
cont = true;
if (tries++ > 20) {
throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR,
"", e);
}
try {
Thread.sleep(50);
} catch (InterruptedException e2) {
Thread.currentThread().interrupt();
}
}
} catch (KeeperException.NoNodeException e) {
// we must have failed in creating the election node - someone else must
// be working on it, lets try again
if (tries++ > 20) {
throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR,
"", e);
}
cont = true;
try {
Thread.sleep(50);
} catch (InterruptedException e2) {
Thread.currentThread().interrupt();
}
}
}
//得到leader的seq,并检查自己是不是leader
int seq = getSeq(leaderSeqPath);
checkIfIamLeader(seq, context, false);
return seq;
}