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的更多相关文章

  1. raft如何实现leadership transfer

    leadership transfer可以把raft group中的leader身份转给其中一个follower.这个功能可以用来做负载均衡,比如可以把leader放在性能更好的机器或者离客户端更近的 ...

  2. etcd raft library设计原理和使用

    早在2013年11月份,在raft论文还只能在网上下载到草稿版时,我曾经写过一篇blog对其进行简要分析.4年过去了,各种raft协议的讲解铺天盖地,raft也确实得到了广泛的应用.其中最知名的应用莫 ...

  3. etcd raft如何实现成员变更

    成员变更在一致性协议里稍复杂一些,由于不同的成员不可能在同一时刻从旧成员组切换至新成员组,所以可能出现两个不相交的majority,从而导致同一个term出现两个leader,进而导致同一个index ...

  4. etcd raft library

    https://github.com/coreos/etcd/tree/master/raft import "github.com/coreos/etcd/raft" ----- ...

  5. 彻底搞懂etcd raft选举、数据同步

    etcd raft选举机制 etcd 是一个分布式的k/V存储系统.核心使用了RAFT分布式一致性协议.一致性这个概念,它是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的服 ...

  6. etcd raft 处理流程图系列1-raftexample

    最近在看raft相关的代码和实现,发现etcd的raft模块在实现上还是比较灵活的,但缺点就是需要用户实现比较多的功能,如存储和网络等,同时带来的优点就是不会对用户的存储和传输作限制.网上对该模块的描 ...

  7. etcd raft如何实现Linearizable Read

    Linearizable Read通俗来讲,就是读请求需要读到最新的已经commit的数据,不会读到老数据. 对于使用raft协议来保证多副本强一致的系统中,读写请求都可以通过走一次raft协议来满足 ...

  8. etcd raft 处理流程图系列3-wal的存储和运行

    存储和节点的创建 raftexample中的存储其实有两种,一个是通过raft.NewMemoryStorage()进行创建的raft.raftStorage,关联到单个raft节点,另一个是通过ne ...

  9. etcd raft 处理流程图系列2-transport

    本章给出了raftexample中使用的传输层代码,补全了上一节中传输层与raft节点(raft server和channel server)的交互细节.下图中流程的核心在于传输层中的streamRt ...

随机推荐

  1. [视频]K8飞刀 BadUSB Teensy自动种马演示教程

    [视频]K8飞刀 Teensy USB自动种马演示教程 链接: https://pan.baidu.com/s/13bM1XSLrhlf90FDmPGfo1g 提取码: gy2q 源码:https:/ ...

  2. Linux Shell常用shell命令

    Linux Shell常用shell命令 一.文件.目录操作命令 1.ls命令 功能:显示文件和目录的信息 ls 以默认方式显示当前目录文件列表 ls -a 显示所有文件包括隐藏文件 ls -l 显示 ...

  3. 使用Charles抓取APP之HTTPS请求

    Charles是一款非常好用的抓包工具,通常使用它来进行APP开发抓包调试,尤其是HTTPS请求. 一.安装Charles 去官网(https://www.charlesproxy.com/)下载软件 ...

  4. 网络IP地址

    IP地址分类 A类网络的IP地址范围为1.0.0.1-127.255.255.254: B类网络的IP地址范围为:128.1.0.1-191.255.255.254: C类网络的IP地址范围为:192 ...

  5. Java并发编程笔记之CyclicBarrier源码分析

    JUC 中 回环屏障 CyclicBarrier 的使用与分析,它也可以实现像 CountDownLatch 一样让一组线程全部到达一个状态后再全部同时执行,但是 CyclicBarrier 可以被复 ...

  6. cmd命令窗口连接mysql的命令大全

    连接:mysql -h主机地址 -u用户名 -p用户密码 (注:u与root可以不用加空格,其它也一样)断开:exit (回车) 创建授权:grant select on 数据库.* to 用户名@登 ...

  7. 微信小程序中this指向作用域问题this.setData is not a function报错

    在微信小程序中我们一般通过以下方式来修改data中的数据 this.setData({ index1: e.detail.value }) 比如在函数里面修改数据 bindFaChange1: fun ...

  8. JavaWeb学习(三十)———— 数据库连接池

    一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...

  9. KVM虚拟化原理与基础应用示例

    一.KVM简介 Kernel-based Virtual Machine的简称,是一个开源的系统虚拟化模块,自Linux 2.6.20之后集成在Linux的各个主要发行版本中.它使用Linux自身的调 ...

  10. windows server 证书的颁发与IIS证书的使用

    最近工作业务要是用服务器证书验证,在这里记录下一. 1.添加服务器角色 [证书服务] 2.一路下一步直到证书服务安装完成; 3.选择圈选中的服务器证书 4.点击[创建证书申请] 5.填写信息 6.下一 ...