Raft 协议
可用性与一致性
为了向用户提供更好的服务体验,现代软件架构越来越注重系统的可用性availability问题。正是在这种趋势的驱动下,微服务与容器化技术才能在今天大行其道。
而高可用架构的前提就是冗余。一个高可用服务必然由多个进程组成,这些进程互为备份,部分进程失效不会导致整个服务不可用。
如果服务是有状态的,那么每个进程都需要维护自己的一个状态副本。为了保证有状态进程的可替代性,如何维护这些副本的一致性consistency成为了至关重要的问题。
以提供锁服务的分布式协调服务为例,这类服务必须满足一下两个特性:
- 高可用:服务失效会导致下游服务不可用
- 强一致:下游服务观察到不一致的状态会导致锁失效
根据分布式数据库的CAP理论,同时实现这个特性是困难的:
- Consistency 一致性
- Availability 可用性
- Partition 网络分区
在网络通信正常的时候,分布式数据库可以同时保证 C 与 A
在发生网络分区(进程间无法正常通信)的时候,数据库必须在 C 和 A 中做出权衡:
- AP 系统:保证可用性,牺牲一致性,每个节点可以对外服务,但整个数据库会处于不一致的状态
- CP 系统:保证一致性,牺牲可用性,每个节点拒绝对外服务,但整个数据库会始终保持一致的状态
在 CAP 的框架下,我们似乎陷入了一个两难的境地:实现一个 CA 的系统是不可能的吗?在回答这个问题前,首先要指出 CAP 理论存在的一个问题:
CAP 理论在权衡时仅考虑了 3 个因素,而忽略了其他的指标,比如:性能、实现复杂度、机器数量...
举个例子:一种流行的说法是 ZooKeeper 是一个 CP 系统。然而,在 ZooKeeper 集群中,只要有半数以上的节点之间能够正常通信,集群仍然能够正常对外提供服务。这意味着:ZooKeepr 在网络发生分区的情况下,依然是可用且一致。
在发生网络分区时,如果要保证系统的可用且一致,需要付出一些额外的代价。以 ZK 为例子,其付出的的代价就是更多的机器资源(必须部署 3 个以上的节点)与复杂度(使用一致性算法)。
共识问题
所谓共识Consensus,就是在某件事情上达成一致意见。分布式系统的共识问题可以表述为:
系统中一个或多个进程提出一个提案
Proposal,然后通过共识算法从中选择一个提案作为最终结果。

以上图中的场景为例:图中是一个多主的分布式数据库,同时允许多个节点接收写操作请求,并且两者会彼此交换修改指令以保证数据的一致性。
刚好在某个时刻,两个客户端同时发起对同个记录的变更操作,因此可能同时存在两种不同的更新顺序(提案)。为了保证数据副本的一致性,两个数据库必须在更新顺序上达成一致(共识)。
进程间为了达成共识,必须遵循一套相同的机制对提议进行选择,从而保证最终选定Chosen的提案是一致的,这类协议就是共识算法Consensus algorithm。
容错
由于运行环境的不确定性,系统故障总是是不可避免的,一个实用的共识算法必须能够在不确定的环境中,保障分布式系统的:
- 安全性
Safety:所有进程收敛到一致的合法状态 - 容错性
Fault-tolerance:少量进程崩溃,系统可持续运行
在分布式系统中,可能出现的故障大致可以分为两类:
- 非拜占庭故障
Byzantine fault
进程间通过不可靠的网络来传输消息- 进程在运行过程中可能出现卡顿、宕机、重启,但是不会发送错误的消息
- 消息在传输过程中可能丢失、重复、失序,但是不会损坏或被篡改
- 拜占庭故障
Non-Byzantine fault
系统中可能出现恶意的进程,故意向其他进程发出错误的讯息
引发其他进程出现异常的行为,导致整个系统失效
因此共识算法又可以分为拜占庭容错与非拜占庭容错两类。
前者主要是应用于区块链领域,通过高昂的计算开销来杜绝进程作恶的可能性,功能强大但不适合用于提供高性能的一致性保障。
后者主要是为数据管理服务,通过额外的安全性假设,减少容错开销,从而能够提供高性能的一致性保障。
接下来要解析的分布式一致性协议都属于非拜占庭共识算法。
原文:https://www.cnblogs.com/buttercup/p/12873512.html