Raft 与 PBFT(到底为什么要用 PBFT)

相关链接:https://www.zhihu.com/search?type=content&q=PBFT%20%E4%B8%8E%20RAft共识算法系列之一:raftpbft算法,美团技术团队),介绍了两者基本流程,点到了两者的核心区别,但没有细致分析(当 raft 节点拜占庭时,raft 导致的失败——不一致场景,换用 pbft 如何避免这种情况)

raft 算法和 pbft 算法是私链和联盟链中经典的共识算法,本文主要介绍了 raft 和 pbft 算法的流程和区别。 raft 和 pbft 算法有两点根本区别:

  1. raft 算法从节点不会拒绝主节点的请求,而 pbft 算法从节点在某些情况下会拒绝主节点的请求 ;
  2. raft 算法只能容错故障节点,并且最大容错节点数为 (n-1)/2 ,而 pbft 算法能容错故障节点和作恶节点,最大容错节点数为 (n-1)/3 。

本文没有涉及算法正确性和收敛性的证明,从算法设计的角度来讲,是需要做这两方面工作的


流程的对比上,对于 leader 选举这块, raft 算法本质是谁快谁当选,而 pbft 算法是按编号依次轮流做主节点。对于共识过程和重选 leader 机制这块,为了更形象的描述这两个算法,接下来会把 raft 和 pbft 的共识过程比喻成一个团队是如何执行命令的过程,从这个角度去理解 raft 算法和 pbft 的区别。

一个团队一定会有一个老大和普通成员。对于 raft 算法,共识过程就是:只要老大还没挂,老大说什么,我们(团队普通成员)就做什么,坚决执行。那什么时候重新老大呢?只有当老大挂了才重选老大,不然生是老大的人,死是老大的鬼。

对于 pbft 算法,共识过程就是:老大向我发送命令时,当我认为老大的命令是有问题时,我会拒绝执行。就算我认为老大的命令是对的,我还会问下团队的其它成员老大的命令是否是对的,只有大多数人 (2f+1) 都认为老大的命令是对的时候,我才会去执行命令。那什么时候重选老大呢?老大挂了当然要重选,如果大多数人都认为老大不称职或者有问题时,我们也会重新选择老大。


作者:美图技术团队
链接:https://zhuanlan.zhihu.com/p/35847127
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Raft 安全性子约束(括号内描述拜占庭节点如何破坏各个自约束)

safety : 即在任何情况下,系统都不能出现不可逆的错误,也不能向客户端返回错误的内容 。 Raft 通过保证如下属性来保证安全性。
  • Election Safety:在一个任期内最多只能选出一位*。(拜占庭节点会向多个候选者投票,使得多个候选者都以为得到了超半数投票)
  • Leader Append-Only:Leader从不覆盖或删除日志中的条目;它只添加新entry (*)
  • Log Matching:如果两个节点上的某个log entry的log index相同且term相同,则它们所存储的命令是相同的,且在该index之前的所有log entry应该都是相同的。依赖于:
• leader 在某一 term 的任一位置只会创建一个 log entry ,且 log entry 是 append-only 。( 拜占庭 leader 可能会向备份节点发送针对不同 entry 的复制、提交请求,但是在 PBFT 中,由于节点在收到主节点的 PRE-PREPARE之后,会转发给其余节点PREPARE,只有当某个节点收到2f+1(至少 f+1是来自真的)个针对相同任期、相同序号、相同内容的PREPARE之后,才会对该消息进入PREPARED 状态,也就是说,如果主节点发了不相同的PRE-PREPARE,会由于转发而被其余节点知道,另外,如果某消息(v,x,m)能进入PREPARED状态,说明主节点至少向f+1个诚实节点发送了一致的PRE-PREPARE, 即使向其他节点发送了不一致的(v,x,m'),后续也不可能会有节点对该不一致消息进入PREPARED 状态 ,为什么呢?因为:进入PREPARED 状态至少需要来自 2f+1个节点的PREPARE,即对PRE-PREPARE(v,x,m')的认可,但是协议规定节点在对PRE-PREPARE(v,x,m)认可之后,不能再对PRE-PREPARE(v,x,m')进行认可,诚实的节点都会旅行这一规则,因此假设恶意节点最多的情况,即有2f+1个诚实节点,f 个恶意节点,不可能既有 f+1个诚实节点对PRE-PREPARE(v,x,m)认可,又有f+1个诚实节点对PRE-PREPARE(v,x,m')认可,因为此时诚实节点的数量为2f+1,这会产生矛盾。上面是对 f 个节点恶意这一具体情况的讨论,那么不防再讨论恶意节点<f 的情况(f-1个拜占庭,2f+2个诚实等等),进入PREPARED 状态至少需要来自 2f+1个节点的PREPARE,那么这里面有>f+1个诚实节点的消息(f+2等),那么将不可能既有 f+2个诚实节点对PRE-PREPARE(v,x,m)认可,又有f+2个诚实节点对PRE-PREPARE(v,x,m')认可,因为 2f+4>2f+2)   • leader 在 AppendEntries 中包含最新 log entry 之前的一个 log 的 term 和 index ,如果 follower 在对应的 term index 找不到日志,那么就会告知 leader不一致(拜占庭节点破坏这一规范)

 

  • Leader Completeness:如果一个log entry在某个任期被提交(committed),那么这条日志一定会出现在所有更高term的leader的日志里面。即保证leader包含最新的已提交的日志。

• 一 个日志被复制到 majority 节点才算 committed • 一个节点得到 majority 的投票才能成为 leader ,而节点 A 给节点 B 投票的其中一个前提是, B 的日志不能比 A 的日志旧 。 • 上面两点都提到了 majority : commit majority and vote majority ,根据 Quorum ,这两个 majority 一定是有重合的,因此被选举出的 leader 一定包含了最新的 committed 的 日志     • State Machine Safety : 如果 节点将某一 位置 ( index in log entries ) 的 log entry 应用到了状态机,那么其他节点在同一位置不能应用不同的日志。 简单点来说,所有节点在同一 位置应该 应用同样的日志 。 • 某个 leader 选举成功之后,不会直接提交前任 leader 时期的日志,而是通过提交当前任期的日志的时候“顺手”把之前的日志也提交了,避免发生复制到大多数节点(或者说可能已经应用)的日志被回滚的情况 • 如果 leader 被选举后没有收到客户端的请求呢,论文中有提到,在任期开始的时候发立即尝试复制、提交一条空的 log                                          
上一篇:linux中时间精度的获取问题【转】


下一篇:JDK源码分析系列之四:HashSet深入理解以及源码分析