强一致性、顺序一致性、弱一致性和共识

                   强一致性、顺序一致性、弱一致性和共识

提到分布式架构就一定绕不开“一致性”问题,而“一致性”其实又包含了数据一致性事务一致性两种情况,本文主要讨论数据一致性(事务一致性指ACID)

复制是导致出现数据一致性问题的唯一原因。

如果只用一台数据库来处理所有的写入和读取请求,就一定不存在数据一致性的问题。 但在中大型项目中,我们却经常需要将一份数据存储在超过一台数据库中(即复制),原因有三:

1、即使一部分数据库出现故障,系统也能正常工作(高可用)

2、使数据与用户在地理上接近(降低延迟)

3、扩展可以处理读请求的机器数量(可扩展性、提高读取吞吐量)

本文假设数据集非常小,每台机器的空间都足够保存整个数据集,否则将会引入一个新的话题“分区”。本文假设使用单领导者的主从复制算法,即只有一台数据库可以处理写请求(称为领导者或主库),所有数据库都可以处理读请求(除主库外其他都是追随者或从库)。

1. 一致性(Consistency) 

一致性(Consistency)是指多副本(Replications)问题中的数据一致性。可以分为强一致性、顺序一致性与弱一致性。 

1.1强一致性(Strict Consistency) 

也称为:

  原子一致性(Atomic Consistency)

  线性一致性(Linearizable Consistency)

扫描二维码关注公众号,回复: 9236763 查看本文章

两个要求:

  • 任何一次读都能读到某个数据的最近一次写的数据。
  • 系统中的所有进程,看到的操作顺序,都和全局时钟下的顺序一致。

简言之,在任意时刻,所有节点中的数据是一样的。

例如,对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。

 1.2 顺序一致性(Sequential Consistency)

两个要求:

  • 任何一次读都能读到某个数据的最近一次写的数据。
  • 系统的所有进程的顺序一致,而且是合理的。即不需要和全局时钟下的顺序一致,错的话一起错,对的话一起对。

 1.3 弱一致性

数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。

最终一致性就属于弱一致性。

最终一致性

不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。

简单说,就是在一段时间后,节点间的数据会最终达到一致状态。

最终一致性根据更新数据后各进程访问到数据的时间和方式的不同,又可以区分为:

1 因果一致性(Casual Consistency)。如果进程A通知进程B它已更新了一个数据项,那么进程B的后续访问将返回更新后的值,且一次写入将保证取代前一次写入。与进程A无因果关系的进程C的访问,遵守一般的最终一致性规则。
2 “读己之所写(read-your-writes)”一致性。当进程A自己更新一个数据项之后,它总是访问到更新过的值,绝不会看到旧值。这是因果一致性模型的一个特例。
3 会话(Session)一致性。这是上一个模型的实用版本,它把访问存储系统的进程放到会话的上下文中。只要会话还存在,系统就保证“读己之所写”一致性。如果由于某些失败情形令会话终止,就要建立新的会话,而且系统的保证不会延续到新的会话。
4 单调(Monotonic)读一致性。如果进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值之前的值。
5 单调写一致性。系统保证来自同一个进程的写操作顺序执行。要是系统不能保证这种程度的一致性,就非常难以编程了。

2. 共识(Consensus)

共识问题中所有的节点要最终达成共识,由于最终目标是所有节点都要达成一致,所以根本不存在一致性强弱之分。

例如,Paxos是共识(Consensus)算法而不是强一致性(Consistency)协议。共识算法没有一致性级别的区分。

另一种说法

强一致性 与 弱一致性 

其实只有两类数据一致性,强一致性与弱一致性。强一致性也叫做线性一致性,除此以外,所有其他的一致性都是弱一致性的特殊情况。所谓强一致性,即复制是同步的,弱一致性,即复制是异步的。

用户更新网站头像,在某个时间点,用户向主库发送更新请求,不久之后主库就收到了请求。在某个时刻,主库又会将数据变更转发给自己的从库。最后,主库通知用户更新成功。

如果在返回“更新成功”并使新头像对其他用户可见之前,主库需要等待从库的确认,确保从库已经收到写入操作,那么复制是同步的,即强一致性。如果主库写入成功后,不等待从库的响应,直接返回“更新成功”,则复制是异步的,即弱一致性。

强一致性可以保证从库有与主库一致的数据。如果主库突然宕机,我们仍可以保证数据完整。但如果从库宕机或网络阻塞,主库就无法完成写入操作。

在实践中,我们通常使一个从库是同步的,而其他的则是异步的。如果这个同步的从库出现问题,则使另一个异步从库同步。这可以确保永远有两个节点拥有完整数据:主库和同步从库。 这种配置称为半同步。

最终一致性

开篇提到,容忍节点故障只是需要复制的一个原因。另两个原因是可扩展性和降低延迟。

单领导者的主从复制算法要求所有写入都由单个节点处理,但只读查询可以由任何节点处理。对于读多写少的场景,我们往往创建很多从库,并将读请求分散到所有的从库上去。这样能减小主库的负载,并允许向最近的节点发送读请求。当然这只适用于异步复制——如果尝试同步复制,则单个节点故障将使整个系统无法写入。

当用户从异步从库读取时,如果此异步从库落后,他可能会看到过时的信息。这种不一致只是一个暂时的状态——如果等待一段时间,从库最终会赶上并与主库保持一致。这称为最终一致性。

最终两个字用得很微妙,因为从写入主库到反映至从库之间的延迟,可能仅仅是几分之一秒,也可能是几个小时。

发布了319 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_41563161/article/details/104190694