一致性:过载的术语
一致性这个词重载的很厉害,在不同的语境和上下文中,它其实代表着不同的东西:
- 在事务的上下文中,比如ACID里的C,指的就是通常的一致性(Consistency)
- 在分布式系统的上下文中,例如CAP里的C,实际指的是线性一致性(Linearizability)
- 此外,“一致性哈希”,“最终一致性”这些名词里的“一致性”也有不同的涵义。
这些一致性彼此不同却又有着千丝万缕的联系,所以经常会把人绕晕。
在事务的上下文中,一致性(Consistency) 的概念是:对数据的一组特定陈述必须始终成立。即不变量(invariants)。具体到分布式事务的上下文中这个不变量是:所有参与事务的节点状态保持一致:要么全部成功提交,要么全部失败回滚,不会出现一些节点成功一些节点失败的情况。
在分布式系统的上下文中,线性一致性(Linearizability) 的概念是:多副本的系统能够对外表现地像只有单个副本一样(系统保证从任何副本读取到的值都是最新的),且所有操作都以原子的方式生效(一旦某个新值被任一客户端读取到,后续任意读取不会再返回旧值)。
线性一致性这个词可能有些陌生,但说起它的另一个名字大家就清楚了:强一致性(strong consistency) ,当然还有一些诨名:原子一致性(atomic consistency),立即一致性(immediate consistency) 或 外部一致性(external consistency ) 说的都是它。
这两个“一致性”完全不是一回事儿,但之间其实有着微妙的联系,它们之间的桥梁就是共识(Consensus)
简单来说:
- 分布式事务一致性会因为协调者单点引入可用性问题
- 为了解决可用性问题,分布式事务的节点需要在协调者故障时就新协调者选取达成共识
- 解决共识问题等价于实现一个线性一致的存储
- 解决共识问题等价于实现全序广播(total order boardcast)
- Paxos/Raft 实现了全序广播
具体来讲:
为了保证分布式事务的一致性,分布式事务通常需要一个协调者(Coordinator)/事务管理器(Transaction Manager)来决定事务的最终提交状态。但无论2PC还是3PC,都无法应对协调者失效的问题,而且具有扩大故障的趋势。这就牺牲了可靠性、可维护性与可扩展性。为了让分布式事务真正可用,就需要在协调者挂点的时候能赶快选举出一个新的协调者来解决分歧,这就需要所有节点对谁是Boss达成共识(Consensus)。
共识意味着让几个节点就某事达成一致,可以用来确定一些互不相容的操作中,哪一个才是赢家。共识问题通常形式化如下:一个或多个节点可以提议(propose)某些值,而共识算法决定采用其中的某个值。在保证分布式事务一致性的场景中,每个节点可以投票提议,并对谁是新的协调者达成共识。
共识问题与许多问题等价,两个最典型的问题就是:
- 实现一个具有线性一致性的存储系统
- 实现全序广播(保证消息不丢失,且消息以相同的顺序传递给每个节点。)
Raft算法解决了全序广播问题。维护多副本日志间的一致性,其实就是让所有节点对同全局操作顺序达成一致,也其实就是让日志系统具有线性一致性。 因而解决了共识问题。(当然正因为共识问题与实现强一致存储问题等价,Raft的具体实现etcd
其实就是一个线性一致的分布式数据库。)
总结一下:
线性一致性是一个精确定义的术语,线性一致性是一种 一致性模型 ,对分布式系统的行为作出了很强的保证。
分布式事务中的一致性则与事务ACID中的C一脉相承,并不是一个严格的术语。(因为什么叫一致,什么叫不一致其实是应用说了算。在分布式事务的场景下可以认为是:所有节点的事务状态始终保持相同)
分布式事务本身的一致性是通过协调者内部的原子操作与多阶段提交协议保证的,不需要共识;但解决分布式事务一致性带来的可用性问题需要用到共识。
推荐阅读: