DDIA-一致性与共识(一致性保证与可线性化)

Posted by keys961 on March 11, 2019

1. 一致性保证

关于最终一致性:多副本存储中,不一致现象是暂时的(但时长未知),最终会一样,即“收敛”。但它的一致性保证太弱,可以说基本没有。

关于弱保证:如read-after-write/read-your-write、monotonic reads等保证下,需要清楚了解系统局限性。

分布式一致性模型与事务隔离级别:相似,存在某些重叠,但也有显著区别:

  • 前者:针对延迟和故障等问题,协调副本之间的状态
  • 后者:处理并发执行事务时的各种临界条件

2. 可线性化——最强分布式一致性模型

可线性化思想:让一个系统看起来好像只有一个数据副本,且所有的操作都是原子的。

可线性化 = 原子一致性 = 强一致性…,CAP中的C即线性化

2.1. 如何达到可线性化

  • 若写write(x, v_new)已完成,则完成后的所有的读(包括不同客户端)read(x)必须读到v_new
  • 若在写write(x, v_new)过程中,值会跳变,若其中的读read(x)读到了新值v_new,之后的所有读(包括不同客户端)必须返回v_new

根据返回结果,可推断操作可能执行的时间点,这些时间点相连,其指向不可能向后。

可线性化与可串行化的区别:

  • 可线性化:单个操作,单个对象,实时顺序。它代表单个对象读写的最新值保证(因此无法避免幻读)。此外,可线性化的组合也是可线性化的。
  • 可串行化:多个操作,多个对象,任意总顺序。它是事务的隔离属性。它确保事务执行的结果和某个串行执行结果相同即可(串行执行顺序可能和实际执行顺序不同)。但它不包含可线性化的“实时”概念。

可串行化和可线性化可以同时达到(严格可串行化),基于2PL或实际串行执行的实现都是可线性化的,而基于快照的可串行化是不可线性化的(因为从快照读肯定不是线性化

2.2. 哪些场景需要线性化

2.2.1. 加锁与主节点选举

有些系统,集群中只能有一个主节点(否则脑裂),常见方法是使用(每个节点尝试获得锁,获得到的就是主节点)。

而锁的实现必须满足可线性化,即“所有节点必须知道哪个节点拥有锁,且结果一致”。

Paxos, Raft等共识算法可确保可线性化。

2.2.2. 约束与唯一性保证

数据有唯一性约束(如SQL的UNIQUE约束)时,应该保证线性化(两个相同的写入应该一个返回错误),其和加锁本质相同。

其它场景的约束也需要所有节点就某个新值达成强一致(如银行账户等)。

2.2.3. 跨通道的时间依赖

当存在不同信道,且信道间存在竞争,如下图所示,文件存储需要保证线性化,才能保证第5,6步读到的是最新的图片。

fig9-5

也可以用更弱的等级,如read-after-write,但会增加额外复杂性。

2.3. 实现线性化系统

2.3.1. 不同复制方案下的可线性化

主从复制:若读取从主节点或者更新是同步的,可满足可线性化

共识算法:与主从复制机制相似,但通过一些措施防止脑裂和过期副本,安全实现可线性化

多主复制:通常无法线性化,因为副本在多节点上并发写入,且异步复制

无主复制:可能无法线性化,取决于quorum配置,宽松的quorum会违背线性化,甚至严格的quorum也会违背线性化

此外基于墙上时钟的LWW几乎肯定是非线性化,因为墙上时钟不能保证与实际事件顺序一致。

2.3.2. 线性化与严格quorum

通常,读写遵循严格的quorum,应该是可线性化的,然而在出现不确定的的网络延迟时,就会出现竞争条件,不满足线性化。

例子:$n=3, w=3, r=2$,时序如下图,第二次读不满足线性化。

fig9-6

解决方案:

  • 读时进行同步的读修复
  • 写前必须读取quorum节点获取最新值

但会显著降低性能,很少有采用。且这种方式不能支持线性化的“比较和设置”(CAS)操作(需要共识算法支持)。

2.4. 线性化的代价

网络中断(网络分区)迫使我们在可线性化和可用性中做出选择。

对于多主复制系统,不保证可线性化,但保证了可用性;

对于主从复制系统,若主从间网络中断,则:

  • 若可用,从节点提供的数据是旧的,不满足可线性化
  • 若满足可线性化,则需要主节点同步复制到从节点,所以必须返回错误给客户端,导致不可用

2.4.1. CAP理论

实际上任何一个数据中心内部,只要有不可靠的网络,就都会有违背线性化的风险,所以在满足出现网络故障时:

  • 要求线性化,则必须等待网络修复,或之间返回错误——不可用
  • 要求可用,则每个副本可独立处理请求——结果不满足线性化

CAP:C(线性一致性),A(可用),P(允许网络分区)之中只能满足2个。实际上P肯定存在,因此更准确的是:网络分区情况下,选择一致还是可用

CAP应用范围较窄:只考虑一种一致性模型(线性化)和一种故障(网络分区,节点仍活动但相互断开)。

2.4.2. 不选择线性化的理由

线性化是一个有用的保证,但很少有系统选择支持它,因为它的读写性能非常差(原因在于网络延迟)。而弱一致性模型则快很多。

因此,放弃线性化是为了提高性能,而不是为了保住容错特性。