文章目录
1 基本原则与设计理念
1.1 原CAP含义
CAP 是对“Consistency/Availability/Partition Tolerance"的一种简称,其内在含义如下:
- 强一致性(Consistency):即在分布式系统中的同一数据多副本情形下,对于数据的更新操作体现岀的效果与只有单份数据是一样的。
- 可用性(Availability):客户端在任何时刻对大规模数据系统的读/写操作都应该保证在限定延时内完成。
- 分区容忍性(Partition Tolerance):在大规模分布式数据系统中,网络分区现象,即分区间的机器无法进行网络通信的情况 是必然会发生的,所以系统应该能够在这种情况下仍然继续工作。
CAP原则的精髓:对于一个大规模分布式数据系统来说,CAP三要素不可兼得,同一个系统至多只能实现其中的两个,而必须放宽第3个要素来保证其他两个要素被满足。即要么AP,要么CP,抑或AC,但是不存在CAP。
为何在分布式环境下CAP三者不可兼得?
对此问题可做棋盘推演,这样问题的关键转换为:假设存在网络分区的情形,若已得到P,即容忍网络分区的存在,那么C和A是否可以兼得。可以分为两种情形来进行进一步推演。
(1)情形1:如果在这个分布式系统中数据无副本,那么系统必然满足强一致性条件,因为只有独本数据不会出现数据不一致的可能。此时C和P两要素具备,但是如果系统发生了网络分区状况或者机器宕机,必然导致某些数据不可访问,此时可用性条件是不能被满足的,即在此情形下获得了CP系统,但CAP不可同时满足。
(2)情形2:
- 如果系统中数据有副本(见图 ),假设变量x存在两份副本并分别存储在不同机器上,最初数据保持一致,其值都为v1。
- 在Time=t1的时刻,在机器1上发生对x的数值更新操作,此操作要将x的值赋为v2。
- 时间推移到Time=t2时刻,机器1上的x已经被赋予新值v2,如果此时未发生网络分区状况,系统可以将x的新值v2同步到机器2,达到数据一致性要求。
- 但是如果此时发生了网络分区(即:P已发生,两台机器无法通信,x的新值将无法同步到机器2),这个时刻我们不得不在C或A之间做个权衡和选择。
- 如果希望系统高可用(选择A),那么对于读取机器2上的x的查询请求必须在限定时间内返回值,此时返回的并非是最新的值v2,所以出现了数据不一致的问题(抛弃C)。
- 如果选择强一致性(选择C),那么在两台机器恢复通信并将数据同步到一致状态前,对于机器2的x读请求必须予以拒绝,此时无法保证系统的可用性(抛弃A)。
- 所以不论选择哪一个,必然以牺牲另外一个因素作为代价,也就是说要么AP,要么CP,但是没有完美的CAP。
综上所述,在分布式环境下CAP是不可兼得的。在设计具体分布式架构技术方案时,必须在一致性和可用性方面做出取舍,要么选择强一致性减弱服务可用性,要么选择高可用性容忍弱一致性。
然而,CAP原则的提岀者Eric Brewer在2012年对此提出了强烈质疑。
1.2 CAP 重装上阵(CAP Reloaded)
Eric Brewer在2012年发表的文章中指出:实践过程中应用CAP理论时不得不在三要素中选择两个而牺牲另外一个的做法具有误导性。
-
首先,在实际系统中,网络分区(P)岀现的概率是很小的,并不应该为了容忍这种小概率事件而在设计之初就选择放弃A或者放弃C,即正常状况下应该兼顾CAP三要素。
-
其次,即使是必须在AC之间做出取舍的时候,也不应该是粗粒度地在整个系统级别进行取舍,而是应该考虑系统中存在不同的子系统,甚至应该在不同的系统运行时或者在不同的数据间进行灵活的差异化的细粒度取舍。
-
再次,CAP三者并非是绝对二元式地有或没有,而是应该将其看作连续变量,即可以看作在一定程度上的有或没有。
因此可以采取如下的应用CAP策略:
- 在绝大多数系统未产生网络分区的情形下,应该尽可能保证AC两者兼得,也即大多数情况下考虑CAP三者兼得。
- 当发生网络分区时,系统应该能够识别这种状况并对其进行正确处理。
- 在未发生网络分区的情形下,在系统各种操作进行过程中,整个系统状态保持一致(状态S),即整个系统满足CAP三要素。
- 当发生网络分区后,系统识別出此种情形并明确记载各个分区的各自状态。为保证可用性,每个分区进入分区模式并各自执行本分区内的各种操作,此时产生了两个分区模式下的状态s1和s2,这两个状态是不一致的,即整个系统满足AP要素。
- 当网络分区解决后,整个系统转入分区恢复状态,在恢复过程中,融合s1和s2形成新的满足一致性要求的新状态s’,此时系统再次进入满足CAP三要素的状态。
1.3 ACID 原则
ACID是关系数据库系统采纳的原则,也是一种简称,其代表含义如下。
- 原子性(Atomicity):是指一个事务要么全部执行,要么完全不执行。
- 一致性(Consistency ):事务在开始和结束时,应该始终满足一致性约束条件。
【注】:这里需要注意的是,尽管CAP和ACID都有关于一致性的定义,但是两者的含义是不同的。 - 事务独立(Isolation ):事务之间需要序列化执行。
- 持久性(Durability ):事务的持久性是指事务运行成功以后,对系统状态的更新是永久的,不会无缘由地回滚撤销。
1.4 BASE 原则
数据库系统采纳ACID原则,获得高可靠性和强一致性。而大多数大数据环境下的云存储系统和NoSQL系统则采纳BASE原则,这种原则与ACID原则差异很大,具体而言,BASE原则是指:
- 基本可用(Basically Available )
- 软状态或者柔性状态(Soft State)
- 最终一致性(Eventual Consistency )
注:BASE原则与ACID原则不同,前者是通过牺牲强一致性来获得高可用性。尽管现在大多数的 NoSQL系统采纳了 BASE原则,但是有一点值得注意:NoSQL系统与云存储系统的发展过程正在向逐步提供局部ACID特性发展 。
1.5 CAP/ACID/BASE 三者的关系
关系: ACID和BASE原则是在明确提出CAP理论之前关于如何对待可用性和强一致性的两种完全不同的设计哲学。ACID更强调数据一致性,而BASE更强调可用性。 由以上所述可知,CAP与BASE两者的一致性显而易见;但相比较而言,CAP和ACID的关系就稍显复杂了。具体如下。
差异:
- 在出现网络分区情形下,很明显ACID中的C所要求的一致性约束是无法保证的,所以在网络分区解决后需要通过一定手段来恢复ACID中要求的一致性。
- 当出现网络分区时,ACID中的事务独立(I)只能在多个分区中的某个分区执行。
- 当出现网络分区时,多个分区都可以各自进行ACID中的数据持久化(D)操作,当网络分区解决后,如果每个分区都提供持久化记录,则系统可以根据这些记录发现违反ACID 一致性约束的内容并给予修正。
总之,当CAP中的P岀现时,如果每个网络分区都尽可能执行ACID,那么对于网络分区问题解决后数据的一致性恢复是有很大帮助的。
1.6 幂等性(Idempotent)
定义:在抽象代数里,对于一元运算来说,满足 f(f(x))=f(x)
条件的运算即可称为满足幂等性;对于二元运算来说,如果满足 f(x,x)=f(x)
条件的运算也可称为满足幂等性。分布式系统中的幂等性是指:调用方反复执行同一操作与只正确执行一次操作效果相同。典型的例子比如Zookeeper和Raft就支持很多操作的幂等性,以此来保证在复杂环境下反复调用相同操作,其系统内部状态仍然正确无误。
2 一致性模型分类
1.强一致性:在数据库的所有进程中,当更新完成,后续所有访问都将获得更新值。
2. 弱一致性:即系统不能保证后续访问都将获得更新值。
3. 最终一致性:在对x做出操作后,与最终看到新数值之前,存在一个时间片段,在这个时间片段内,数据也许是不一致的,即不一致窗口。
4. 因果一致性:因果一致性发生在进程之间有因果关系依赖的情况下。
进程A与进程C没有因果依赖关系,则遵循最终一致性。
- “读你所写”一致性:读你所写”一致性是因果一致性的特例。更新操作后,进程A后续访问到的都是新数值,其他进程并未受影响。
- 会话一致性:“会话一致性”是“读你所写”一致性的变体。当进程A通过会话与数据库系统连接,同一个会话内,可以保证“读你所写”一致性,若会话终止,进程A的数值会不一定。
- 单调读一致性:最终一致性的另一种变体。如果某个进程读到数据x的一个数值,那么后续所有访问将不会返回任何之前的值。
- 单调写一致性:另外一种最终一致性的变体。对于某个进程来说,单调写一致性可以保证其多次写做操作的序列化,同时也保证了应用开发者的顺利开发。
3 副本更新策略
3.1 同时更新
- 类型A:没有任何协议,可能出现多个节点执行顺序交叉导致数据不一致情况。
- 类型B:通过一致性协议唯一确定不同更新操作的执行顺序,从而保证数据一致性
3.2 主从式更新
3.3 任意节点更新
数据更新请求可能发给多副本中的任意一个节点,然后由这个节点来负责通知其它副本进行数据更新。
请求延时和一致性权衡有以下两种情形:
4 一致性协议
4.1 两阶段提交协议
含义:要么所有备份数据同时更改某个数值,要么都不更改,以此来达到数据的强一致性两类不同实体:唯一的协调者(Coordinator)和众多的参与者(Particpants)两个阶段:表决阶段(Voting)、提交阶段(Commit)
综合两阶段过程中的协调者视角,可以归纳出协调者的有限状态机
综合两阶段过程中的参与者视角,也可归纳出参与者的有限状态机
协调者节点指示参与者节点进行提交等操作时,可能因为有进程陷入崩溃而导致处于阻塞态的对象进入长时间的等待。
为了解决这种情况,可以引入超时判断机制和参与者互询机制:
为了解决长时阻塞,提出了三段提交协议(3PC)
4.2 向量时钟(Vector Clock)
向量时钟是在分布式环境下生成事件之间偏序关系的算法,偏序关系代表事件发生先后顺序导致的事件因果依赖关系语义,通过将时间戳和事件绑定可以用来判定事件之间的因果相关性。
示例:Alice, Ben, Cathy, Dave四个人准备下周聚餐,在时间安排上协调出现了问题。
-
首先,Alice提出Wednesday聚餐,那么对提出这个提议的Alice来说,此时她的时钟向量就是这样的:
date = Wednesday;
vclock = Alice:1
她将这个消息广播给其他三个人注:vclock名字后的数字表示的是版本号,而图中的横线表示的是时间线
-
Ben在收到提议之后,提出自己的提议Tuesday,此时ben的时钟向量就是:
date = Tuesday
vclock = Alice:1, Ben:1
然后将消息发送给Dave:
-
Dave收到之后,回复Ben表示同意Tuesday,此时Dave的时钟向量是:
date = Tuesday
vclock = Alice:1, Ben:1, Dave:1 -
现在Cathy参与进来,建议Thursday,
此时Cathy的时钟向量是:
date = Thursday
vclock = Alice:1, Cathy:1
-
然后将提议发送给了Dave:Dave此时就有了两份有冲突的数据(冲突的原因是Ben和Cathy“同时”修改了最初Alice的数据):
date = Tuesday
vclock = Alice:1, Ben:1, Dave:1
和
date = Thursday
vclock = Alice:1, Cathy:1 -
根据时钟向量的关系判断规则,Dave发现了冲突,因为当前的向量时钟和新接收到的向量时钟上的各个逻辑时钟并不是全部小于或大于。幸运的是,Dave是个有理性的人,选择了Thursday(前面是发现冲突,这里相当于解决冲突,实际系统中解决冲突的方法不同,解决冲突不是向量时钟的内容)。Dave解决冲突并回复给Cathy,此时Dave的向量时钟为:
date = Thursday
vclock = Alice:1, Ben:1, Cathy:1 -
至此,当Alice问Ben和Cathy最新的决定,会收到来自Ben的:
date = Tuesday
vclock = Alice:1, Ben:1, Dave:1
和来自Cathy的:
date = Thursday
vclock = Alice:1, Ben:1, Cathy:1, Dave:2
-
这样,Alice她可以说Dava与Cathy一致修改了自己和Ben的提议,并将Cathy的消息给Ben,Ben就知道它的提议已经被修改。现在,它们愉快的达成了一致。对于整个协商的过程,可以看到冲突的根源在于Ben和Cathy都“同时”修改了Alice的数据,Dave解决了数据冲突(不同问题,解决数据冲突的方法不同),最后它们达成一致。
向量时钟的更新规则:
1、每次修改数据,本节点的版本号加1;
2、每当进程发送消息时,会将自己的向量时钟和消息m同时发送出去;
3、每次同步数据(同步和修改是不一样的写操作),会有三种情况
4.3 RWN协议
对多备份数据如何读写成功进行灵活配置,达到数据一致性。
说明成功写入的备份集合和成功读取的备份集合一定会存在交集,保证了读取操作一定可以读到最新的数据版本。
4.4 Paxos协议
4.4.1 副本状态机模型
在实际实现上述副本状态机中的一致性协议时,往往追求以下几个特性:
- 安全性保证:保证不能做错的事,即非拜占庭模型下,状态机从不返回错误的结果,多个提议中只有一个被选中。
- 可用性保证:只要大多数服务器正常,则整个服务器保持可用。
- 一般情况下,大多数状态机维护Log一致即可快速通知客户端操作成功,这样避免了少数最慢的状态机拖慢整个请求响应速度
4.4.2 Paxos基本概念
Paxos又可以细分为两种:单Paxos和多Paxos。
- 单Paxos,即副本状态机中各个服务器针对Log中固定某个位置的操作命令通过协议达成一致,因为可能某一时刻不同服务器的Log中相同位置的操作命令是不一样的,通过执行协议后使得各个服务器对应某个固定位置的操作命令达成一致。
- 多Paxos则是指这些服务器对应的Log内容中多个位置的操作命令序列通过协议保持一致。
- 多Paxos往是同时运行的多个单Paxos协议共同执行的结果,后文讲解Paxos协议主要以单Paxos为主。
4.4.3 Paxos一致性协议
Paxos协议下不同并行进程可能承担的3种角色如下。
- 倡议者(Proposer) :倡议者可以提出提议(数值或操作命令等)以供投票表决。
- 接受者(Acceptor) :接受者可以对倡议者提出的提议进行投票表决,从众多提议中选出唯一确定的一个。
- 学习者(Learner) :学习者无倡议投票权,但是可以从接受者那里获知是哪个提议最终被选中。
在一致性协议框架中,一个并行进程可以同时承担以上多种角色。