在Go语言里,etcd的clientv3.concurrency包开放了选举方法concurrency.NewElection,可以直接调用。我把选举过程打印出来看,发现其内部逻辑和常规的ZK选主一样。
首先开启一个会话,调用election.Campaign时,在指定目录下创建一个有序id用于排队,并判断自己的id是不是最小值。如果是最小值则成为Leader。会话设置了一个TTL值,如果在TTL的时间内重新建立会话并election.Campaign,则重置TTL计时,给Leader Buff续命。超过TTL则Leader Buff消失。
如果自己的id不是最小值,election.Campaign会阻塞形成排队状态,此时的状态是Follower。election会watch队伍中前一个候选人的id,当它消失时则自己成为最小值,当选Leader并退出排队。如果在会话TTL的时间里重新建立会话并election.Campaign,则重置TTL计时,给Follower排队位置Buff续命。如果超过TTL,election.Campaign内部有个waitDelete方法会清除无效的排队信息,退出排队,给别人让出机会。再次election.Campaign需重新排队。
1 | package main |
output:
1 | worker:1 Follow |
参考资料
Raft算法及etcd/raft的实现思路借鉴
http://atomicer.cn/2019/05/17/etcd-raft%E4%B8%ADraft%E7%AE%97%E6%B3%95%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%80%9D%E8%B7%AF%E5%8F%82%E8%80%83/