开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情
1. 概述
在区块链系统中,共识协议是很重要的一环。Bitcoin提出了POW(工作量证明),以太坊在前段时间完成了共识协议的转换变成了POS(权益证明)。对于不需要货币体系的联盟链和分布式系统来说,传统的一致性算法目前还是首选,比较有名的是PBFT(拜占庭容错)、PAXOS、Raft。这篇文章将在“深入剖析区块链的共识算法 Raft & PBFT”的基础上,讨论Raft和RBFT的区别,同时对两种算法进行对比。
共识算法是什么? 共识算法是用于保证分布式系统一致性的机制。区块链中的一致性可以理解为交易顺序的一致性、账本一致性、节点状态的一致性等。
目前区块链系统中的共识算法概览:
- 公链:POW,POS,DPOS,ripple
- 联盟链:PBFT,RBFT,NoxBFT、HotStuff
- 私链:Raft,Paxos
数据一致性应该如何维护?
分布式数据库系统:PBFT、Paxos、Gossip、Raft
区块链系统:工作量证明:PoW,权益证明算法:PoS、DPoS
2. Raft算法
Raft算法包含三种角色,分别是:跟随者(follower),候选人(candidate)和领导者(leader)。可以简单的理解为Raft制定了一种选举方式,第一个获得超过半数投票的候选人成为leader。
Raft主要可以分为领导者选举、日志复制两个部分,在论文中也介绍了脑裂情况的网络一致性恢复和快照日志的处理。
领导者选举
Raft 使用心跳(heartbeat)触发Leader选举。当服务器启动时,Leader向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat,就会发起一次Leader选举。Follower将其当前term加一然后转换为Candidate。它首先给自己投票并且给集群中的其他服务器发送RequestVoteRPC。当赢得了多数的选票,成功当选为Leader后,它会重复开头的操作,即定期向所有Followers发送heartbeat维持其统治;
日志复制
Leader选出后,就开始接收客户端的请求。Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他Follower节点发起AppendEntries RPC以复制该日志条目。当这条日志被复制到大多数服务器上,Leader将这条日志应用到它的状态机并向客户端返回执行结果。
3. PBFT算法
PBFT(实用BFT算法)算法的提出主要是为了解决拜占庭将军问题。当两军作战时,如果有作恶节点的情况下,忠诚的将军如何保证消息的一致性。这个问题有解的条件是,在信道可靠的情况下,叛徒的数量不能大于等于所有将军数量的1/3。
Raft算法仅支持容错故障节点,但是对于PBFT算法而言除了容错故障还需要支持作恶节点。极端情况下,有f个问题节点和f个故障节点,问题节点f个被排除,剩下的正常节点需要比故障节点多一个,使得集群达成共识。所以,所有类型的节点数量加起来就是3f+1个。
3.1 算法流程
PBFT算法的基本流程主要有以下四步:
- 客户端发送请求给主节点
- 主节点广播请求给其它节点,节点执行PBFT算法的三阶段共识流程。
- 节点处理完三阶段流程后,返回消息给客户端。
- 客户端收到来自f+1个节点的相同消息后,代表共识已经正确完成。
核心流程:
PBFT算法的核心三个阶段分别是pre-prepare阶段(预准备阶段),prepare阶段(准备阶段),commit阶段(提交阶段)。图中的C代表客户端,0,1,2,3代表节点的编号,打叉的3代表可能是故障节点或者是问题节点,这里表现的行为就是对其它节点的请求无响应。0是主节点。整个过程大致是:
-
首先,客户端向主节点发起请求,激活主节点的服务操作
-
主节点0收到客户端请求,采用三阶段协议向从节点广播请求。主节点会向其它节点发送pre-prepare消息。
-
Pre-prepare阶段:节点收到pre-prepare消息后,会有两种选择,一种是接受,一种是不接受。
- 一种典型的情况就是如果一个节点接到了一条pre-prepare消息,消息里的v和n在之前收到里的消息是曾经出现过的,但是d和m却和之前的消息不一致,或者请求编号不在高低水位之间,这时候就会拒绝请求。拒绝的逻辑就是主节点不会发送两条具有相同的v和n,但d和m却不同的消息。
-
Prepare阶段:节点同意请求后会向其它节点发送prepare消息。这里要注意一点,同一时刻不是只有一个节点在进行这个过程,可能有n个节点也在进行这个过程。因此节点是有可能收到其它节点发送的prepare消息的。在一定时间范围内,如果收到超过2f个不同节点的prepare消息,就代表prepare阶段已经完成。
-
Commit阶段:于是进入commit阶段。向其它节点广播commit消息,同理,这个过程可能是有n个节点也在进行的。因此可能会收到其它节点发过来的commit消息,当收到2f+1个commit消息后(包括自己),代表大多数节点已经进入commit阶段,这一阶段已经达成共识,于是节点就会执行请求,写入数据。
-
-
处理完毕后,节点会返回消息给客户端。客户端等到f+1的相同的响应结果,则认为此次请求成功完成。
这就是PBFT算法的全部流程,三阶段分为pre-prepare,prepare,commit。
pre-prepare和prepare阶段用于对在同一视图中发送的请求完全排序,即使提出请求排序的primary为虚假节点也是如此。prepare和commit阶段用于确保在视图之间对提交的请求进行完全排序
4. 比较分析
| 对比点 | Raft | PBFT |
|---|---|---|
| 适用环境 | 私链 | 联盟链 |
| 算法通信复杂度 | O(n),follower无需沟通 | O(n^2),节点之间通信 |
| 最大故障和容错节点 | 故障节点:2f+1<=N | 容错节点:3f+1<=N |
| 流程对比 | 1.谁先触发超时时间,获得半数以上的选票谁当选 2.从节点之间不交流,leader节点发的消息总是对的,除非宕机 | 1.按照编号依次作主节点 2.从节点之间交流,如果大多数人认为leader有问题会重新选举leader |
5. 总结
本文主要介绍了Raft和PBFT算法的流程和区别。raft和pbft算法有两点根本区别:
- Raft算法从节点不会拒绝主节点的请求,而PBFT算法从节点在某些情况下会拒绝主节点的请求 ;
- Raft算法只能容错故障节点,并且最大容错节点数为(n-1)/2,而PBFT算法能容错故障节点和作恶节点,最大容错节点数为(n-1)/3。
PS:RBFT:在PBFT的基础上加了batch打包流程,和其他优化措施