19

etcd-raft 源码分析

 4 years ago
source link: https://zhuanlan.zhihu.com/p/49792009
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

etcd-raft 源码分析

人类的悲欢并不相通,我只觉得他们吵闹

本篇文章主要分析etcd-raft的代码实现,关于raft协议的细节,参考:

Etcd-raft的实现包含以下功能:

  • Leader election
  • Log replication/Log compaction
  • Membership changes/Leader transfer
  • Linearizable / Lease read

值得注意的是,etcd-raft并没有实现消息的网络发送和接收,而是把消息保存在内存中,需要用户自己定义网络传输层,实现消息的发送和接收。同时,etcd-raft定义了Storage接口,用户使用者自己定义存储层。

1. etcd-server的启动

raftNode启动了一个包含for-select结构的goroutine,三个case分支的作用分别如下:

1.1 时钟驱动

通过r.ticker.CTime类型的Channel)监听时钟事件, 然后调用自身的tick方法,raft的时钟主要用来处理heartbeatelection timeout

1.2 消息监听

监听消息是否到达: Ready是raft的核心结构体,下面我们看一下Ready 各个字段的含义:

  • SoftState包含了两个字段:Lead,RaftState。Lead表示当前Leader的ID,RaftState表示节点当前的状态(Follower,Leader,Candidate ...)
  • HardState包含了:Term,Vote,Commit等字段。代表了消息发送前的状态细节,比如commit索引值等,待消息发送后要做一些相应处理
  • ReadStateslinearizable read有关,后续再做解释
  • Entries是要在log replication前存储到stable storage的日志实例
  • Snapshot是要存储到stable storage的快照例
  • CommittedEntriesreplication给集群中其他成员的日志实例
  • Messages是要发送给其他成员的消息实例
  • MustSync标识HardStateEntries是否必须写入到stable storage

2. node / raft的初始化

在etcd-raft中,有两个重要的概念:node和raft。

node是一个StateMachine,而raft代表StateMachine当前的State 。

node代表了etcd集群中的一个节点,负责时钟驱动,事件触发,IO调用;raft负责维护当前自身节点的状态:任期,Leader,日志Commit等。在 etcd集群中,node 实例和raft实例是一对一的关系。

2.1 node是如何启动的

通过newRaft初始化raft实例,并将自身状态设置为:Follower。通过newNode初始化node,并通过node.run(raft)实现node实例与raft实例的启动。通过下面的run方法可以发现,noderaft之间通过Channel进行交互。

我们看一下node.run的核心代码:

看到这里我们应该明白了node中的Channel是通过tick来驱动运作的,并且上面代码中出现了我们前面提到的 Ready对象的构造:

3、 消息发送

heartbeat message 是由tick触发的,heartbeat的触发频率即为tick的频率:

既然是tick驱动,那我们看一下raft在接收到tick之后的行为。

根据raft 实例当前不同的状态,tick会触发不同的行为:Follower,Candidate,PreCandidate会触发 tickElection,Leader 会触发tickHeartbeat

tickElection会触发MessageHup类型的消息,tickHeartbeat会触发pb.MsgCheckQuorum, pb.MsgBeat 类型的消息。

而上述过程中出现的 Step方法是raft实例消息处理的核心方法:

同样,根据当前raft实例角色(Leader, Follower, Candidate)的不同,处理消息的类型和方式也不同,具体实现上对应不同的stepFunc:

stepLeader为例,Leader处理的消息主要包括:

pb.MsgBeat, pb.MsgCheckQuorum , pb.MsgProp, pb.MsgReadIndex, pb.MsgAppResp, pb.MsgHeartbeatResp,pb.MsgSnapStatus,pb.MsgUnreachable,pb.MsgTransferLeader

4、存储

etcd-raft的存储内容主要包含三部分内容:

4.1、raftLog

raft本身就像一个StateMachine,通过log-replication来实现成员之间状态的一致。

  • Storage是一个接口,即使用者需要自己实现的存储方案,在raft/example中有一个MemoryStorage的实现,感兴趣可以自己看一下。
  • unstable:已经生成或发出,尚未获得集群认可的日志
  • commited:已获得集群至少二分之一成员认可的日志
  • applied:已经应用到 StateMachine的日志

4.2、binLog

  • binlog 和 snapshot主要数据的迁移和恢复;

4.3、 kvStore

  • 用来存储client端提交的数据,在raft/example中用hashmap代替

待续 。。。

参考链接:

https://www.cockroachlabs.com/blog/scaling-raft/​www.cockroachlabs.com


Recommend

  • 72
    • www.opscoder.info 7 years ago
    • Cache

    etcd中的raft实现 | jasper的blog

    在之前的一篇文章中我们了解了怎么使用ectd的raft的库来实现一个简单的分布式存储,但是只看了应用端对raft的调用以及周边,但是对于raft的库的内部没有做涉及,那么这篇文章我们就深入到raft内部看看其实现的细节。

  • 7
    • www.codedump.info 3 years ago
    • Cache

    Etcd Raft库的工程化实现

    Etcd Raft库的工程化实现 2021-05-15 分布式 ...

  • 8
    • www.codedump.info 3 years ago
    • Cache

    Etcd Raft库的日志存储

    之前看etcd raft实现的时候,由于wal以及日志的落盘存储部分,没有放在raft模块中,对这部分没有扣的特别细致。而且,以前我的观点认为etcd raft把WAL这部分留给了上层的应用去实现,自身通过Ready结构体来通知应用层落盘的数据,这个观点也有失偏...

  • 6
    • keys961.github.io 3 years ago
    • Cache

    etcd-raft (3): Raft的启动与选主

    上一篇讲了etcd-raft的日志和消息数据结构及其实现,本文就深入它对于Raft协议的实现,这一次挑选的是选主。 2. 节点启动 在看选主前,首先看下etcd-raft是如何启动的。 2.1. 数据结构 这里涉及到的数据...

  • 11
    • keys961.github.io 3 years ago
    • Cache

    etcd-raft (7): Raft线性一致读

    这里最后说明一下论文的最后部分“线性一致读”在etcd的实现。 2. 线性一致 CAP中的C即线性一致,它指的是:系统写操作提交成功后,之后的读取都会得到最新的数据。 即:在分布式系统上实现寄存器语义...

  • 9
    • keys961.github.io 3 years ago
    • Cache

    etcd-raft (1): 基于Raft的K-V存储样例

    Raft论文之前读过(Paxos这个读不懂的),也做过一定的练习实现,不过那个有点naive了,真要看还得看大名鼎鼎的etcd-raft。 不过这里先不看etcd-raft的具体实现,本文先从它提供的raftexample入手,它基于etcd-raft实现了简单的分布式K-V...

  • 9
    • keys961.github.io 3 years ago
    • Cache

    etcd-raft (2): Raft日志与消息

    Raft中的一个重要组件就是日志,另一个比较重要的是Raft节点传输的消息。 在etcd中,日志的实现是raftLog,消息的定义是Message。本文就看下这些组件的实现。 2. Raft日志 etcd-raft的Raft日志由raf...

  • 6
    • keys961.github.io 3 years ago
    • Cache

    etcd-raft (4): Raft的复制和心跳

    上一篇讲了etcd-raft的选主协议,这次探究一下另一个重要协议:复制和心跳。 2. 日志复制 选主好了后,Leader就可以同步日志到Follower上。这里涉及到的消息类型有:MsgProp, MsgApp, MsgAppResp。

  • 10
    • keys961.github.io 3 years ago
    • Cache

    etcd-raft (6): Raft快照

    上一篇讲了etcd-raft的集群配置变更。本文顺着论文讲快照。 2. 快照内容 etcd-raft的快照内容会这么选择: 假如unstable中存在了快照,返回它保存的 否则返回Storage中的快照

  • 6
    • www.cnblogs.com 2 years ago
    • Cache

    etcd/raft选举源码解读 - Wildhunt

    ETCD-raft笔记 该篇博客基于etcd v3.5.7版本,首先会简单介绍etcd/raft对Raft选举部分的算法优化,然后通过源码分析etcd/raft的选举实现。 1. etcd对于raft选举算法优化措施 该优...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK