Talk about Consistency and Consensus
ACID 中的一致性 我们现在关注的是其中的 C,即一致性 Consistency。它是什么意思呢?通俗地说,它指的是任何一个数据库事务的执行,都应该让整个数据库保持在「一致」的状态: ACID 中的「一致性」,是对于整个数据库的「一致」状态的维持。抽象来看,对数据库每进行一次事务操作,它的状态就发生一次变化。这相当于把数据库看成了状态机,只要数据库的起始状态是「一致」的,并且每次事务操作都能保持「一致性」,那么数据库就能始终保持在「一致」的状态上 (Consistency Preservation)。 所谓状态是不是「一致」,其实是由业务层规定的。比如转账的例子,“转账前后账户总额保持不变”,这个规定只对于「转账」这个特定的业务场景有效。如果换一个业务场景,「一致」的概念就不是这样规定了。所以说,ACID 中的「一致性」,其实是体现了业务逻辑上的合理性,并不是由数据库本身的技术特性所决定的。 为了让事务总是能保持 ACID 的一致性,我们需要在实现上考虑哪些因素呢? 出错情况 (failure/error) 事务本身的实现逻辑可能存在错误,这需要应用层进行恰当的编码来保证。 需要 ACID 中的 A(原子性)来保障。简言之,原子性保障了事务的执行要么全部成功,要么全部失败,而不允许出现“只执行了一半”这种“部分成功”的情况。 并发行为 需要 ACID 中的 I(隔离性)来保障了。什么是隔离性呢?它对于并发执行的多个事务进行合理的排序,保障了不同事务的执行互不干扰。换言之,隔离性这种特性,能够让并发执行的多个事务就好像是按照「先后顺序」执行的一样。 Summary ACID 中的一致性,是个很偏应用层的概念。这跟 ACID 中的原子性、隔离性和持久性有很大的不同。原子性、隔离性和持久性,都是数据库本身所提供的技术特性;而一致性,则是由特定的业务场景规定的。 要真正做到 ACID 中的一致性,它是要依赖数据库的原子性和隔离性的(应对错误和并发)。 最后,ACID 中的一致性,甚至跟分布式都没什么直接关系。它跟分布式的唯一关联在于,在分布式环境下,它所依赖的数据库原子性和隔离性更难实现。 总之,ACID中的一致性,是一个非常特殊的概念。除了数据库事务处理,它很难扩展到其它场景,也跟分布式理论中的其它「一致性」概念没有什么关系。 分布式事务与共识算法的关系 共识问题 (consensus problem)。这是分布式系统中的一个十分基础而核心的问题,它表示如何在分布式系统中的多个节点之间就某事达成共识。 网上通常提到的「分布式一致性协议」,或者「分布式一致性算法」,一般来说就是解决这里的共识问题的算法。 这些算法或协议,经常包含 Paxos 之类,但也可能包括两阶段提交协议 (2 PC)或三阶段提交协议 (3 PC)。 ACID 中的原子性,要求事务的执行要么全部成功,要么全部失败,而不允许出现“部分成功”的情况。在分布式事务中,这要求参与事务的所有节点,要么全部执行 Commit 操作,要么全部执行 Abort 操作。换句话说,参与事务的所有节点,需要在“执行 Commit 还是 Abort”这一点上达成一致(其实就是共识)。这个问题在学术界被称为原子提交问题(Atomic Commitment Problem),而能够解决原子提交问题的算法,则被称为原子提交协议(Atomic Commitment Protocal,简称ACP)。2PC 和3PC,属于原子提交协议两种不同的具体实现。 我们可以发现原子提交问题和共识问题的关联: 共识问题,解决的是如何在分布式系统中的多个节点之间就某个提议达成共识。 原子提交问题,解决的是参与分布式事务的所有节点在“执行 Commit 还是 Abort”这一点上达成共识。 所以,原子提交问题是共识问题的一个特例。(?) 一些细节的不同,可能导致非常大的差异。当我们描述共识问题的时候,我们说的是在多个节点之间达成共识;而当我们描述原子提交问题的时候,我们说的是在所有节点之间达成共识。这个细微的差别,让这两类问题,几乎变成了完全不同的问题(谁也替代不了谁): ...