Stolon-sentinel的Leader选举过程
选举原理
通过阅读etcd提供的Campaign方法,发现选举过程基于了Etcd的几个特性,就可以完成自动选主:
- MVCC:key存在版本属性,没被创建时版本号为0
- CAS操作:结合MVCC,可以实现竞选逻辑,if(version == 0) set(key,value),通过原子操作,确保只有一台机器能set成功;
- Lease租约:可以对key绑定一个租约,租约到期时没预约,这个key就会被回收;
- Watch监听:监听key的变化事件,如果key被删除,则重新发起竞选。
流程梳理
在Sentinel选主时,核心代码逻辑如下:
首先定义一个了选举接口,可以针对不同的场景实现(在这里只介绍使用etcd方式进行leadership
)
RunForEletion方法:进行Leader选举
Leader方法:返回Leader节点value值
Stop方法:停止处理
Sentinel结构体定义如下:
- election:选举接口
- leader:bool类型,标识当前sentinel节点是否为leader
- leadershipCount:leader任期,每次竞选成功后会+1
当Sentinel启动时,首先会启动一个goroutine进行Leader选举
进入electionLoop方法查看具体选举过程
可以看到,调用RunForElection方法去竞争Leader,成为Leader的Sentinel将leader和leadershipCount字段更新
进入RunForElection方法,看一下具体实现:
继续看campaign方法:
加上注释后的代码:
1 | // 使用 etcdv3 实现的分布式选举功能 |
Campaign方法是etcd提供的leadership核心方法,进去看下具体是怎么实现的(代码太多了就不贴图片了….)
1 | // Campaign puts a value as eligible for the election on the prefix |
该方法首先创建一个 key,然后用事务来进行竞选操作。如果当前 key 的 revision 是 0,表示该 key 没有被其他会话占用,那么就将当前 session 设置为 leader,并将 val 写入该 key 的 value。如果该 key 的 revision 不是 0,那么就从 etcd 中获取该 key 的 value 和 revision,判断它是否是当前 session 的 leader。如果是,则继续保持当前 session 为 leader;否则,使用 Proclaim 函数尝试成为 leader,如果失败则使用 Resign 函数放弃竞选。
在函数执行完成后,如果当前 session 成为了 leader,它将会监视比当前 key revision 小的 key,等待这些 key 被删除。如果有一个或多个 key 被删除,那么这些 key 的删除操作将会返回。如果在等待期间 context 被取消,那么当前 session 将会放弃 leadership。
总之,该方法的作用是让多个会话竞选成为 leader,从而实现分布式系统中的 leader 选举