etcd raft如何实现leadership transfer
leadership transfer可以把raft group中的leader身份转给其中一个follower。这个功能可以用来做负载均衡,比如可以把leader放在性能更好的机器或者离客户端更近的机器上。
对于一个大规模分布式系统来说,负载均衡非常重要。然而raft本身在选主方面必须要求新主包含所有的意境committed的log,从这点上看,在选主阶段,不能加入自定义的选主逻辑。而paxos协议不太一样,paxos对选主没有要求,任何一个成员都可以成为主,选主协议可以自己实现。paxos leader当选后,从其他成员把commit的log拉过来即可。所以为了这个feature,raft作者提出了一个方案作为raft的扩展。
大概原理就是保证transferee(transfer的目标follower)拥有和原leader有一样新的日志,期间需要停写,然后给transferee发送一个特殊的消息,让这个follower可以马上进行选主,而不用等到election timeout,正常情况下,这个follower的term最大,当选,原来的leader变为备。
还是一样看看etcd实现的raft library怎么做,省略无关代码
首先应用通过如下函数来启动leader transfer,其中lead是当前的leader,transferee是目标leader,在任意一个成员上调用即可。
func (n *node) TransferLeadership(ctx context.Context, lead, transferee uint64) {
select {
// manually set 'from' and 'to', so that leader can voluntarily transfers its leadership
case n.recvc <- pb.Message{Type: pb.MsgTransferLeader, From: transferee, To: lead}:
case <-n.done:
case <-ctx.Done():
}
}
跑raft的goroutine从recvc中拿出message,首先做各种各样的检查,比如是否已经有transfer leader正在进行中,如果正在进行,目标是谁,然后做相应的处理。如果没有,则调用一下代码:
r.leadTransferee = leadTransferee
if pr.Match == r.raftLog.lastIndex() {
r.sendTimeoutNow(leadTransferee)
r.logger.Infof("%x sends MsgTimeoutNow to %x immediately as %x already has up-to-date log", r.id, leadTransferee, leadTransferee)
} else {
r.sendAppend(leadTransferee)
}
首先将目标leader保存在leadTransferee中,标示着有transfer正在进行,后续如果有请求propose进来,会检查:
if r.leadTransferee != None {
r.logger.Debugf("%x [term %d] transfer leadership to %x is in progress; dropping proposal", r.id, r.Term, r.leadTransferee)
return
}
这里相当于停写。
回到上面:
- 如果transferee和leader的log一样新,则给transferee发送MsgTimeoutNow类型的消息,告诉transferee可以立即选主,不需要等到election timeout。transferee端:
r.campaign(campaignTransfer)
raft为了防止出现网络分区的情况下,candidate频繁增加term从而导致term爆炸,在选主的时候新增加了一个PreVote阶段,通过了这个阶段才会真正开始Vote,这里,由于transferee明确知道是transfer,就没有必要采用这种两阶段的选主,所以传入的参数是campaignTransfer
- 如果leader发现transferee的日志落后,则给transferee append日志,leader在收到响应MsgAppResp后,会检查:
// Transfer leadership is in progress.
if m.From == r.leadTransferee && pr.Match == r.raftLog.lastIndex() {
r.logger.Infof("%x sent MsgTimeoutNow to %x after received MsgAppResp", r.id, m.From)
r.sendTimeoutNow(m.From)
}
如果发现transferee已经日志最新,则同样,给transferee发送MsgTimeoutNow
最后,看看etcd如何调用:
func (s *EtcdServer) transferLeadership(ctx context.Context, lead, transferee uint64) error {
now := time.Now()
interval := time.Duration(s.Cfg.TickMs) * time.Millisecond
plog.Infof("%s starts leadership transfer from %s to %s", s.ID(), types.ID(lead), types.ID(transferee))
s.r.TransferLeadership(ctx, lead, transferee)
for s.Lead() != transferee {
select {
case <-ctx.Done(): // time out
return ErrTimeoutLeaderTransfer
case <-time.After(interval):
}
}
// TODO: drain all requests, or drop all messages to the old leader
plog.Infof("%s finished leadership transfer from %s to %s (took %v)", s.ID(), types.ID(lead), types.ID(transferee), time.Since(now))
return nil
}
调用TransferLeadership后,每隔一段时间检查是否transfer成功,要么超时,直接返回。
etcd raft如何实现leadership transfer的更多相关文章
- raft如何实现leadership transfer
leadership transfer可以把raft group中的leader身份转给其中一个follower.这个功能可以用来做负载均衡,比如可以把leader放在性能更好的机器或者离客户端更近的 ...
- etcd raft library设计原理和使用
早在2013年11月份,在raft论文还只能在网上下载到草稿版时,我曾经写过一篇blog对其进行简要分析.4年过去了,各种raft协议的讲解铺天盖地,raft也确实得到了广泛的应用.其中最知名的应用莫 ...
- etcd raft如何实现成员变更
成员变更在一致性协议里稍复杂一些,由于不同的成员不可能在同一时刻从旧成员组切换至新成员组,所以可能出现两个不相交的majority,从而导致同一个term出现两个leader,进而导致同一个index ...
- etcd raft library
https://github.com/coreos/etcd/tree/master/raft import "github.com/coreos/etcd/raft" ----- ...
- 彻底搞懂etcd raft选举、数据同步
etcd raft选举机制 etcd 是一个分布式的k/V存储系统.核心使用了RAFT分布式一致性协议.一致性这个概念,它是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的服 ...
- etcd raft 处理流程图系列1-raftexample
最近在看raft相关的代码和实现,发现etcd的raft模块在实现上还是比较灵活的,但缺点就是需要用户实现比较多的功能,如存储和网络等,同时带来的优点就是不会对用户的存储和传输作限制.网上对该模块的描 ...
- etcd raft如何实现Linearizable Read
Linearizable Read通俗来讲,就是读请求需要读到最新的已经commit的数据,不会读到老数据. 对于使用raft协议来保证多副本强一致的系统中,读写请求都可以通过走一次raft协议来满足 ...
- etcd raft 处理流程图系列3-wal的存储和运行
存储和节点的创建 raftexample中的存储其实有两种,一个是通过raft.NewMemoryStorage()进行创建的raft.raftStorage,关联到单个raft节点,另一个是通过ne ...
- etcd raft 处理流程图系列2-transport
本章给出了raftexample中使用的传输层代码,补全了上一节中传输层与raft节点(raft server和channel server)的交互细节.下图中流程的核心在于传输层中的streamRt ...
随机推荐
- .NET手记-定义类和接口的扩展方法
对于iOS开发者来说,使用扩展方法是家常便饭.因为有很多的类是有系统框架的定义的,我们不能修改或者不想修改他们的源码,但是我们又想要给他添加一些扩展方法来使用.这时定义扩展方法就是很有用的方式了,正如 ...
- scrapy爬虫--苏宁图书
实现业务逻辑如下: 1. 创建scrapy项目,并生成 爬虫2. 在suning.py中实现Schedul 和 Spider业务逻辑3. 修改start_urls为正确的初始请求地址4. 构造pars ...
- Java 单元测试顺序执行
坑死我了,原来@Before会执行多次. 通过函数名可以实现顺序执行,执行顺序和函数的位置无关. import org.junit.Before; import org.junit.BeforeCla ...
- ArrayList的实现原理
ArrayList的线性复杂度是1.想确定一个数据,直接通过索引进行访问.实际上这个过程和数组是非常相似的.ArrayList在整个使用过程中,如果想要高效操作,最好设置一个数组的大小.在个数固定的情 ...
- 新电脑一般javaweb配置
下个jdk (官网)1.打开我的电脑--属性--高级--环境变量 2.新建系统变量JAVA_HOME 和CLASSPATH 变量名:JAVA_HOME 变量值:C:\Program Files\Jav ...
- bigdata-01-应用
1, 基本概念 在互联网技术发展到现今阶段,大量日常.工作等事务产生的数据都已经信息化,人类产生的数据量相比以前有了爆炸式的增长,以前的传统的数据处理技术已经无法胜任,需求催生技术,一套用来处理海量数 ...
- apache log4j打印日志源码出口
Throwable.class: public void printStackTrace(PrintStream s) { synchronized (s) { s.println(this); St ...
- openssl genrsa
openssl系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html genrsa用于生成RSA私钥,不会生成公钥,因为公钥提取自私钥,如果需要查 ...
- 获取微信的access_tokey,处理json格式的数据
#region 获取微信凭证 public string GetAccessToken(string wechat_id) { string accessToken = ""; D ...
- C# QuartZ使用实例写成服务
官方学习文档:http://www.quartz-scheduler.net/documentation/index.html 官方的源代码下载:http://sourceforge.net/proj ...