关于raft:实践案例丨基于-Raft-协议的分布式数据库系统应用

10次阅读

共计 4286 个字符,预计需要花费 11 分钟才能阅读完成。

摘要:简略介绍 Raft 协定的原理、以及存储节点 (Pinetree) 如何利用 Raft 实现复制的一些工程实践经验。

1、引言

在华为分布式数据库的工程实际过程中,咱们实现了一个计算存储拆散、底层存储基于 Raft 协定进行复制的分布式数据库系统原型。上面是它的架构图。

计算节点生成日志通过封装后通过网络下发到存储节点,在 Raft 层达成统一后日志被利用到状态机 wal Engine, 实现日志的回放和数据的存储管理。

上面简略介绍一下 Raft 的原理、以及存储节点 (Pinetree) 如何利用 Raft 实现复制的一些工程实践经验。

2、Raft 的原理

2.1 Raft 的基本原理

Raft 算法所有以领导者为准,实现一系列值的共识和各节点日志的统一。上面重点介绍一下 Raft 协定的 Leader 选举、log 复制 和 成员变更。

Raft 的选举机制:

协定为每个节点定义了三个状态:Leader、Candidate、Follower,将工夫定义为 Term,每个 Term 有一个 ID。Term 相似逻辑时钟,在每个 Term 都会有 Leader 被选举进去。

Leader 负责解决所有的写申请、发动日志复制、定时心跳,每个 Term 期间最多只能有一个 Leader,可能会存在选举失败的场景,那么这个 Term 内是没有 Leader。

Follower 处于被动状态,负责解决 Leader 发过来的 RPC 申请,并且做出回应。

Candidate 是用来选举一个新的 Leader,当 Follower 超时,就会进入 Candidate 状态。

初始状态,所有的节点都处于 Follower 状态,节点超时后,递增 current Term 进入 Candidate,该节点发送播送音讯 RequestVote RPC 给其余 Follower 申请投票。当收到少数节点的投票后,该节点从 Candidate 进入 Leader。Follower 在收到投票申请后,会首先比拟 Term,而后再比拟日志 index,如果都满足则更新本地 Current Term 而后回应 RequestVote RPC 为其投票。每个 Term 期间,follower 只能投一次票。

Raft 的日志同步机制:

当 Leader 被选举进去后,就能够承受写申请。每个写申请即代表了用户须要复制的指令或 Command。Raft 协定会给写申请包装上 Term 和 Index,由此组成了 Raft 的 Log entry. Leader 把 Log entry append 到日志中,而后给其它的节点发 AppendEntries RPC 申请。当 Leader 确定一个 Log entry 被大多数节点曾经写入日志当中,就 apply 这条 Log entry 到状态机中而后返回后果给客户端。

Raft 成员变更机制:

成员变更就意味着集群节点数的减少或缩小以及替换。Raft 协定定义时思考了成员变更的场景,从而防止因为集群变动引起的零碎不可用。Raft 是利用下面的 Log Entry 和一致性协定来实现该性能。成员的变更也是由 Leader 发动的,Leader 会在本地生成一个新的 Log entry,同时将 Log entry 推送到其余的 Follower 节点。

Follower 节点收到 Log entry 后更新本地日志,并且利用该 log 中的配置关系。少数节点利用后,Leader 就会提交这条变更 log entry。还要思考新就配置的更替所带来的问题。更具体的不再赘述。

2.2 Raft 的开源实现

Raft 的实现有 coreos 的 etcd/raft、kudu、consul、logcabin、cockroach 等。

Etcd、LogCabin、Consul 实现的是单个 Raft 环,无奈做到弹性伸缩。而 kudu 和 cockroach 实现了多个 raft 环。kudu 的 consensus 模块实现了正本的数据复制一致性,kudu 将数据分片称之为 Tablet, 是 kudu table 的程度分表,TabletPeer 就是在 Raft 环外面的一个节点. 一个 Tablet 相当于一个 Raft 环,一个 Tablet 对应一个 Raft Consensus,这些对应 Raft 外面的一个环,Consensus Round 相当于同步的音讯,一个环之间会有多个 Consensus Round 做同步。而 cockroach 则是基于 etcd/raft 实现的多 Raft 环,它保护了多个 Raft 实例,被称之为 multiraft。

因为 Etcd 的 Raft 是目前性能较全的 Raft 实现之一,最早利用于生产环境,并且做到了很好的模块化。其中 Raft 内核局部实现了 Raft 大部分协定,而对外则提供了 storage 和 transport 所用的 interface,对于使用者能够独自实现灵活性较高,用户还能够自主实现 snapshot、wal,Raft 十分便于移植和利用,因而存储节点 Pinetree 采纳了开源的 Etcd 中的 Raft 实现来构建咱们的原型零碎,也便于前期向 Multiraft 演进。。

3、工程实际

3.1 实现 Raft 的存储接口和网络传输

Raft 存储局部指的是 raft- log 的存储,是对日志条目进行长久化的存储,通过 benchmark 测试发现,raft-log 引擎性能是影响整体 ops 的次要瓶颈,为了更灵便的反对底层存储引擎的疾速替换,减少可插拔的存储引擎框架,咱们对底层存储引擎进行解耦。Pinetree 封装了第三方独立存储接口来适配 etcd raft 的 log 存储接口;

通信局部即 Raft Transport、snapShot 传输等,采纳 GRPC+Protobuf 来实现,心跳、日志传输 AppendEntries RPC、选举 RequestVote RPC 等利用场景将 GRPC 设置为简略式,snapShot 设置为流式的模式。

3.2 选举问题

Raft 能够实现自我选举。然而在实践中发现毛病也很显著,Raft 自主选主可能存在如下的问题:

1、不可控:可能随便抉择一个满足 Raft 条件的节点

2、网络闪断导致 Leader 变动

3、节点忙导致的 Leader 变动

4、破坏性的节点

为了避免存储节点 Leader 在不同的 AZ 或者节点间进行切换,Pinetree 采纳的计划是由集群治理模块来指定 Leader。Pinetree 中将 electionTimeout 设置为无穷大,敞开 Follower 可能触发的主动选举过程,所有选举过程由集群治理的倡议选主模块来管制。

3.3 读一致性模型

在 Raft 集群中,个别会有 default、consistent、stale 三种一致性模型,如何实现读操作关乎一致性的实现。个别的做法是将一致性的选择权交给用户,让用户依据理论业务特点,按需抉择,灵便应用。

Consistent 具备最高的读一致性,然而实现上要求所有的读申请都要走一遍 Raft 内核并且将会与写操作串行,会给集群造成肯定的压力。stale 具备很好的性能劣势,然而读操作可能会落到数据有提早的节点上。在 Pinetree 的设计中,集群治理负责保护存储节点的信息,治理所有节点的 Raft 主正本的状态,一方面能够对读申请进行负载平衡,另一方面能够依据 AZ 亲和性、正本上的数据是否有最新的 log 来路由读申请。这样在性能和一致性之间进行了最大的 tradeoff。

3.4 日志问题

Raft 以 Leader 为核心进行复制须要思考几个问题:

1、性能问题,如果 leader 为慢节点会导致长尾

2、日志的同步必须是有序提交

3、切换 leader 时有一段时间的不可用

问题 3 咱们通过集群治理来最大水平的避免 Leader 的切换。

对于问题 2,因为 Pinetree 的日志相似 innodb 的 redo log , 采纳 LSN 来编号的,所以利用到 Pinetree 存储层的的日志必须要保序,不能呈现跳过日志段或日志空洞的状况。这就要求发给 Raft 的日志要做保序解决。计算层产生的 wal log 都对应一个 LSN,LSN 代表的是日志在文件中的偏移量,具备枯燥递增且不间断的特点。因而要求 Wal log 产生的程序和 apply 到 pinetree storage 的程序要保障统一。为了满足这一需要,咱们在计算层和 Raft 层两头减少一个适配层,保护一个队列负责进行排序,同时为了应答计算层主备的切换,对音讯减少 Term 以保障日志不会乱序。Raft 指令还可能会被反复提交和执行,所以存储层要思考幂等性的问题。因为 Pinetree storage 的日志用 LSN 进行编号,所以能够进行反复 apply。

3.5 如何解决假主问题

计算节点须要获取某些元数据信息,每次都必须从 Leader 中读取数据防止出现备机提早。在网络隔离的状况下,老的 leader 不会被动退出,会呈现双主的状况,这个假主可能永远不晓得本人其实曾经不是真正的 Raft 主节点,导致真 Leader 和假 Leader 同时存在并提供读服务,这在无提早零碎是不容许的。

如果每次读申请都走一遍 Raft 协定能够辨认出假主,然而将会重大的影响零碎的性能。

Pinetree 是通过租约(lease)的形式,让一个 Pinetree 主节点在提供服务之前,激进地查看本身在这一时刻是否领有 lease,再决定本身能不能提供读服务。因而,就算拜访了一个 Pinetree 假主,假主也因为没有 lease 而不能提供服务。

3.6 性能问题

波及到性能 Pinetree 思考和优化的中央:

1 如果应用 Raft 算法 保障强一致性,那么读写操作都应该在领导者节点上进行。这样的话,读的性能相当于单机,不是很现实,优化实现了基于 leader+lease 的形式来提供读服务即能保障一致性又不影响性能。

2 优化 raft 参数:in-flight 的数目;transport queue 的数量

3 最大限度的异步化,例如:指令在 raft 达成统一实现长久化后传递给状态机存入音讯队列立刻返回,后续对音讯进行异步并行解析。

4 最大限度的进行 Batch 和 Cache。例如:把一个事务内的写操作缓存到客户端,在事务提交时,再把所有的写打包成一个 batch 与事务 commit 申请一起发送给服务端

#DevRun 开发者沙龙# 9 月 15 日 20:00-21:00,特邀华为云数据库解决方案专家 Sugar,为您打造专场直播“端到端平安可信,华为云数据库解决方案最佳实际”!华为云数据库服务,聚焦互联网、车企、金融、游戏、ISV、地图等行业痛点,满足企业用户多样性计算需要。提供端到端平安可信的解决方案,帮忙企业应用全面云化和智能化。欢送点击直播(http://live.vhall.com/206537223)围观,社区互动(https://bbs.huaweicloud.com/forum/thread-76193-1-1.html)有礼!

正文完
 0