前言
随着互联网系统日益复杂,大多数系统都从单体架构转向分布式架构,而在区块链这样以分布式技术为基础的技术更是高度依赖数据一致性和共识机制。
本文将介绍分布式系统一致性、共识的概念与其在区块链中的实际应用与发展。
分布式系统
一致性问题
随着业务场景的复杂化,同一个业务往往也由多台服务器组成集群提供服务,但如何在这些物理位置和运行状态都不同的系统中达成一致成为了分布式领域的重要问题。
一般而言,分布式系统达成一致有以下三点规范:
- 可终止性
- 约同性
- 合法性
分布式事务需要保障能在有限的时间内达成一致的结果,该结果必须是由某个节点提出的提案且不同节点必须完成相同的决策。
强一致性
想在单体应用或者各个节点的性能、网络带宽等配置在理想状况下做到这一点很容易,然而,在真实的业务场景中,要实现这样的强一致性成本非常高,需要保障系统的绝对稳定性、系统与系统之间的通讯没有延迟,此外,强一致性也会降低系统的性能和拓展性。
在强一致性情况下,任何时刻所有节点中的数据都是一样的。强一致性通常又包括顺序一致性和线性一致性两种。
顺序一致性
顺序一致性要求所有进程的全局执行顺序和各个进程自身的顺序保持一致,但并不要求物理时间上对各个进程保持全局的顺序。因此,这也是一种相对实践性较强的做法。
线性一致性
线性一致性在顺序一致增加了需要对进程间进行全局排序的规则,要求所有时刻所有进程的操作都是实时同步的。这种绝对一致性往往在实践中很难实现,需要通过全局锁或者一些复杂的同步算法实现,且往往以牺牲性能为代价。
弱一致性
而在真实的业务场景里,往往并不需要实时同步这样的绝对一致状态,因此可以容忍部分访问或在一段时间后最终达成一致。这些在某些方面弱化了的一致性称为弱一致性。
共识机制
共识机制是指在分布式系统中多个节点对某个事务达成一致的机制,关于共识的达成,有以下几种理论和原则:
- FLP 不可能原理
- CAP 原则
- ACID 原则
- BASE 理论
- 多阶段提交
FLP 不可能原理
FLP 不可能原理是 Fischer、Lynch 和 Patterson 三位科学家提出的一种理论,即在一个网络可靠但允许节点失效(如停机)的异步系统中,不可能在有限时间内完成共识。
异步是指系统各个节点之间的时间等存在差异性,导致无法判断消息未响应是由于节点故障还是传输过程中的故障,因此无法判断消息是否丢失。
CAP 原则
而在工程实践中,往往会弱化某一部分的需求以满足真实业务场景的需求。CAP 原则就是来解决这一问题,CAP 是指:
- Consistency,一致性
- Availability,可用性
- Partition,分区容错性
分布式系统无法同时保障这三点,最多能保障其中两个特性,那这个原理有哪些实际应用呢?
- AP 系统,在静态网站、非实时性数据库等业务场景下,可以弱化其一致性,如新版本上线后一段时间才达成一致。
- CP 系统,在银行转账等对一致性要求绝对敏感的场景下,可以弱化其可用性,如当系统故障或失败时拒绝服务。
- AC 系统,两阶段提交和一些关系性数据库则弱化网络分区,如 ZooKeeper 等。
ACID 原则
分布式数据库的事务需要牺牲部分可用性来达到一致性,需要遵循 ACID 原则,具体如下:
- Atomicity,原子性。事务的所有操作要么全部执行,要么全部不执行,失败则全部回退。
- Consistency,一致性。事务执行前后状态需要一致,不存在中间状态。
- Isolation,隔离性。多个事务可以并发执行但彼此之间相互独立。
- Durability,持久性。状态改变是永久的。
BASE 原则
BASE 原则是指:
- Basically Available,基本可用
- Soft State,软状态
- Eventual Consistency,最终一致
这是一种牺牲强一致性来实现整个系统的方案,即只保障最终一致性。
多阶段提交
两阶段提交是将事务提交过程分解为预提交和正式提交两个阶段以避免冲突,但仍然存在同步阻塞、单点故障、数据一致性等问题。
TCC 事务机制则主要分为:
- Try 阶段
- Confirm 阶段
- Cancel 阶段
在 Try 阶段对业务进行检查并预留业务资源,在 Confirm 阶段使用资源执行业务,Cancel 阶段取消执行并释放资源。这种方式是对两阶段提交多作了一些业务上的处理,但因为拆分成了三个接口进行,代码复杂性提升了。
三阶段提交引入了超时机制,并在两阶段提交的第一阶段加入了一个尝试预提交环节,主要解决了单点故障和阻塞问题。
共识算法
根据容错类型(是否会有恶意节点),我们把共识算法分为非拜占庭容错(Crash Fault Tolerance, CFT)和拜占庭容错(BFT, Byzantine Fault Tolerance)两种。
CFT (Crash Fault Tolerance)
分布式系统中存在故障节点但不存在错误节点的场景称为 CFT,在这种场景下,消息可能丢失或者重复,但不会错误,在这种条件下如何达成共识是真实世界中非常常见的需求。
Paxos
Paxos 算法原理类似于两阶段提交,设定了三种逻辑节点,提案者、接受者和学习者。由提案者提出提案,接受者对提案进行投票并接受提案,而学习者获取提案结果并广播。
只有提案者提出的提案才可能会批准,而所有节点都可以竞选成为提案者,但每一轮共识只有唯一的一个提案者提提案,这种机制保障了一定的公平性。
然而,Paxos 只能保障一定条件下的共识,当超过半数的节点参与时才会正常运作。
Raft
由于 Paxos 算法实现起来比较困难,出现了许多变体,如 Fast Paxos、Multi-Paxos 等,其中比较有代表性的就是 Raft 算法。
Raft 将一致性过程拆分为领导者选举、日志复制和安全性三个子问题,设定了领导者、候选者和跟随者三种逻辑节点。
所有节点的初始状态都是跟随者,想参与领导者竞选则转变为候选者并提出选举请求,如超过一半票数则成功在本次任期称为领导者。
领导者会处理所有请求并将日志同步至跟随者,并且会定期给所有跟随者发送心跳消息,如果出现故障,心跳消息超时未收到,则会发起新的选举过程。
BFT (Byzantine Fault Tolerance)
Byzantine Fault Tolerance, BFT
拜占庭容错算法则主要是用来处理网络中存在恶意节点的场景,主要是对拜占庭问题的解决,在恶意节点不超过 1/3 的情况下可以有效达成共识,但复杂度非常高(指数级)。
Practical Byzantine Fault Tolerance, PBFT
PBFT 是对 BFT 算法的优化,采用了 RSA 签名算法、消息验证、摘要等密码学技术,结合 Paxos 等相关算法,最后将算法复杂度降到了平方级。
在 PBFT 算法实现中,首先选取(随机/轮换)某个节点,设定其逻辑节点为主节点。主节点在自己的 View 内接收客户端的请求并广播(使用三阶段提交机制,见上文)至其他节点,当所有节点完成处理请求后将结果返回给客户端,如果收到了至少来自 2f + 1 个不同节点的相同结果,则共识完成。
- 尝试预提交:主节点收到消息后进行签名并向其他节点广播
- 预提交:其他节点收到消息后进行核对,合法则向签名并向其他节点广播,其他节点也进行核对
- 正式提交:对消息签名并广播提交状态,如经过 2f + 1 个验证,则系统完成共识
其他
除了 PBFT 外,PoW、PoS、HotStuff 等也广泛应用于比特币、以太坊、Libra 等区块链项目,并在不断优化中,拜占庭容错类算法因为效率不高,大多用于公有链环境,而联盟链则多采用 非拜占庭容错的方式,辅之以权限控制等方式来平衡性能和安全性。
总结
以上就是对分布式系统与区块链共识机制的概念和实际应用总结,之后也会对各类业界投入使用的共识算法作更深入的剖析。