共计 5670 个字符,预计需要花费 15 分钟才能阅读完成。
什么是数据一致性
数据一致性这个单词在平时开发中,或者各种文章中都能常常看见,咱们经常听见什么货色数据不统一了,造成了肯定的损失,赶快修复一下。然而很多同学对一致性具体代表什么意思,他有什么作用仍然不是很理解,明天咱们就来聊聊一致性。
一般来说数据一致性咱们能够分成三类,工夫点一致性,事务一致性,利用一致性。
工夫点一致性(Point in time Consistency)
工夫点一致性我感觉也能够叫做正本一致性,工夫点一致性的定义为:
如果所有相干的数据组件在任意时刻都是统一的,那么能够称作为工夫点一致性。
这个定义如果你理解过 CAP 实践的话,那么你应该不会太生疏。(如果不相熟的同学能够看我这篇文章分布式事务)
在 CAP 中的 C 的定义为对某个指定的客户端来说,读操作能返回最新的写操作。咱们能够发现工夫点并没有规定统一的须要保障是最新的,所以可能有同学会提出疑难工夫点一致性的范畴比 CAP 中的一致性范畴要大一点。其实细想一下如果咱们某个数据组件更新了数据,如果为了满足工夫点一致性,那么咱们所有相干的数据组件的数据都是统一的,所以其余的数据都会变为最新的,那么其实就和 CAP 是一样的,都须要满足如果在某个节点更新了数据,那么在其余节点如果都能读取到这个最新的数据。
当然 CAP 和工夫点一致性并不是齐全的统一: 工夫点一致性的定义中要求所有数据组件的数据在任意时刻都是完全一致的,然而一般来说信息流传的速度最大是光速,其实并不能达到任意时刻统一,总有肯定的工夫不统一,对于咱们 CAP 中的一致性来说只有达到读取到最新数据即可,达到这种状况并不需要严格的任意工夫统一。
这里咱们还须要留神的是这个并不总是用于分布式系统中的,在咱们单个机器中如果有多核处理器,咱们再任意时刻拜访不同处理器对同一变量数据都须要是统一的也能够同样实用。
事务一致性
一致性不仅仅能够示意数据的同时变更或雷同性,还能够用来示意束缚,而咱们的事务一致性就是其中的一种。事务一致性就是咱们平时所说的 ACID 中的 C,其定义如下:
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务胜利地实现,那么零碎中所有变动将正确地利用,零碎处于无效状态。如果在事务中呈现谬误,那么零碎中的所有变动将主动地回滚,零碎返回到原始状态。
事务一致性只能存在在事务开始前的和事务实现之后,在事务过程中数据有可能不统一。举个例子: 比方 A 转 100 元给 B,A 扣减 100,B 加上 100,在事务开始前和事务实现之后都能保障他们的帐是对上的,那么这就是事务一致性。然而在事务过程中有可能会呈现 A 扣减了 100 元,B 没有加上 100 元的状况,这就是不统一。
这里个别的初学者都会把 CAP 和 ACID 中的 C 都会误会成一样的含意,其实他们其中一个示意的数据的雷同,而另一个是用来示意某种束缚。
利用一致性
利用一致性能够看做是束缚一致性中的一种。下面的事务一致性代表的是繁多数据源,如果数据源是多个,比方数据源有多个数据库,文件系统,缓存等。那么就须要咱们利用一致性,这里也看做是分布式事务一致性。
在应用程序中波及多个不同的单机事务,只有在所有的单机事务实现之前和实现之后,数据是完全一致的。比方给用户发送券和积分,券服务和积分服务是两个服务,他们各自有本人单机事务,这两个单机单机事务开始前和实现后都能保障用户的帐是对应上的。然而在这两个单机事务执行过程有可能会呈现只送了券,没有送积分的状况,有可能状态不正确。
这三种一致性能够简略的看做两类,一个是数据正本统一,另一个是数据束缚统一。接下来我更多的会介绍数据正本的统一的类型,而数据束缚的统一,能够参考我之前写过的分布式事务的那篇文章。
一致性的模型
再写这篇文章之前,我始终认为一致性就那么几个常据说的,强统一,弱统一,最终统一。再查问了一些文献资料之后发现一致性的类型真的是十分的多,这里我筛选一些比拟重要的
如果有人问你你晓得哪些一致性模型呢?很多人马上答出,强统一,最终统一。其实一致性的模型远远不止这么点,在《[Operational Characterization of
Weak Memory Consistency Models](https://es.cs.uni-kl.de/publications/datarsg/Senf13.pdf)》这篇论文当中形容了 15 种弱内存统一模型,而在维基百科对内存模型的形容还有更多。
很多一致性的模型最开始是用来形容内存是否统一的,也就是最开始并不是使用于分布式系统当中的。如果咱们的机器是单核的话,那么他的内存肯定是强统一的。如果咱们的机器是多核的话,那么因为处理器并不是间接拜访的内存而是拜访的处理器独享的缓存,那么就有可能会呈现不统一。再分布式中咱们的每个节点其实就能够看成一个独立的处理器,而咱们最后使用于内存一致性模型,也能够使用于咱们分布式系统当中。上面我会从强到弱讲讲一些常见的一致性模型。
线性一致性
线性一致性又叫做原子一致性,强一致性。线性一致性能够看做只有一个单核处理器,或者能够看做只有一个数据正本,并且所有操作都是原子的。在可线性化的分布式系统中,如果某个节点更新了数据,那么在其余节点如果都能读取到这个最新的数据。能够看见线性一致性和咱们的 CAP 中的 C 是统一的。
举个非线性一致性的例子,比方有个秒杀流动,你和你的敌人同时去抢购一样货色,有可能他那里的库存曾经没了,然而在你手机上显示还有几件,这个就违反了线性一致性,哪怕过了一会你的手机也显示库存没有,也仍然是违反了。
线性一致性有什么作用呢?在《DDIA》这本书中形容了上面 3 个作用:
- 加锁与主节点选举: 主从复制零碎须要确保只有一个主节点,否则会产生脑裂。选举新的主节点个别是应用锁: 每个启动的节点都须要取得锁。而这个锁就须要满足可线性化,让所有的节点都同时批准哪个节点有锁。咱们的 ZooKeeper 就能够用来提供分布式锁性能,那么咱们就能够说 ZooKeeper 是满足线性一致性的吗?这个只能说说对了一部分,前面再程序一致性的时候会对 ZK 是什么一致性再次阐明。
- 束缚与唯一性保障: 比方同一个文件目录下不容许有两个雷同的文件名,数据库主键不能反复,这些都须要线性化。其实这些实质和加锁相似,比方雷同的文件名,那其实就是对这个文件名去做一个加锁操作,而后去保留,后保留的天然会出错。
- 跨通道的工夫依赖: 之前的那个抢购的那个例子为什么会被违反呢?起因是因为咱们通过敌人告知这个通道,让咱们提前晓得了这个货物曾经卖完。同样的如果咱们计算机中呈现了多个通道。举个例子,在用户交易的场景下,用户应用了 50 元,那么会在其余额中扣减 50 元,这个时候把这个事件作为一个音讯队列给发送进来,而后短信服务会查问用户的余额而后进行发送短信,如果余额数据库的从库这个时候还没有更新数据,那么这个短信就有可能会取到用户旧的余额。这里呈现不统一的起因就是因为多了一个通道,就和咱们下面敌人告知咱们卖完的通道一样。解决这个方法能够管制某一个通道,比如说将这个用户的余额作为参数给传进去,或者只读主库。秒杀的那个例子中,你能够不要本人的手机,去用敌人的手机。
程序一致性
程序一致性弱于严格一致性。对变量的写操作不肯定要在霎时看到,然而,不同处理器对变量的写操作必须在所有处理器上以雷同的程序看到,这里处理器再分布式系统中能够换成不同的节点。
这里咱们又再回到 Zookeeper 到底是什么一致性?有很多面试题都会问到 Zookeeper 是 CP 还是 AP 呢?很多人都会答复到 Zookeeper 是 CP,其实这个答复并不是很谨严的,咱们从线性一致性中晓得 CAP 中的一致性指的是线性一致性,那咱们就能够说 Zookeeper 是线性一致性的吗?答案是否定的。当咱们写入一个值的时候,会交由 Leader 去解决,Zab 协定只须要保障半数从节点胜利即可,那么就会有节点的数据是老的数据,这样客户端就有可能读出的数据并非是最新的从而毁坏了线性一致性。
Zookeeper 其实实现的是程序一致性,在 ZK 中利用 zxid(ZooKeeper Transaction Id), 实现了整体程序一致性,当然也能够认为 Zookeeper 的的写是线性一致性,读是程序一致性。从节点通过 zxid 程序的接管 leader 的播送,所以 ZK 不能保障所有的信息马上看到,然而最终都会看到。当然 Zookeeper 其实能够实现线性化,在 ZK 中有一个 sync()命令,只有咱们每次读的时候都去调用 sync()强制同步数据,那么咱们都能保障其是最新的。
程序一致性是由 Lamport(Paxos 算法的作者)提出的,最开始只用来定义多解决内存的一致性,在 Lamport 的《How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs》中其定义了什么是程序一致性:
the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program.
这句话的大抵意思是多处理器的执行成果和单个处理器的执行成果是一样的, 每个独立的处理器的操作都会依照指定的程序呈现在操作队列。这个最开始是用于并发编程的,然而让多处理器的执行变得和单处理器确实是没啥作用,起初就用于分布式系统当中。在 ZK 中所有的写操作都会交给 Leader 节点去做,并且所有操作的更新都会依据 zxid 的程序进行更新,这里就是下面所说的指定的程序,这个队列就是依照 zxid 的程序。
因果一致性
因果一致性是弱于程序一致性的一致性模型,程序一致性要求所有的操作的程序都必须依照某个单个处理器 (节点) 的程序,而因果一致性只须要满足有因果关系的操作是程序一致性即可。
怎么了解因果关系呢?简略来说如果有人问你一个问题,那么你给出答案,这两个就是因果关系,但如果你给出答案再问题之前,那么这个就违反了因果关系。
举个简略的例子如果节点 1 更新了数据 A,节点 2 读取数据 A,并更新数据 B,这里的数据 B 有可能是依据数据 A 计算出来的,所有具备因果关系,然而如果节点 3 看到的是先更新的 B,再更新的 A 那么就毁坏了因果一致性。
处理器一致性
处理器一致性是更加弱的一致性模型,他只须要保障处理器看到某个处理器或者多个不同解决对雷同地位的写入都是统一的。不须要思考因果关系,而是对同一个内存或者同一个数据更新须要看到统一的程序。
FIFO 一致性
FIFO 一致性是比处理器一致性还更加弱的一种,它不须要保障对雷同地位的写入是统一的。
是指在一个处理器上实现的所有写操作,将会被以它理论产生的程序告诉给所有其它的处理器;然而在不同处理器上实现的写操作兴许会被其它处理器以不同于理论执行的程序所看到。这个在分布式系统中反映了网络中不同节点的提早可能是不雷同的。为了阐明其和处理器一致性不同有如下例子:
下面这个图中,能够发现是违反了处理器一致性的,为什么呢因为写入程序是 w(x)1,w(x)2 而,p4 应该是先 R(x)1 再 R(x)2。然而这个合乎 FIFO 一致性,FIFO 只须要把本人的产生程序告诉给其余的处理器或者节点,不须要保障同一个值写入程序是统一的。
最终一致性
其实除了强统一以外,其余的一致性都能够看作为最终一致性,只是依据一致性不同模型的不同要求又衍生出了很多具体一致性模型。当然最简略的最终一致性,是不须要关注两头变动的程序,只须要保障在某个工夫点统一即可。只是这个某个工夫点须要依据不同的零碎,不同业务再去掂量。再最终一致性实现之前,有可能返回任何的值,不会对这些值做任何程序保障。
BASE 实践中的 E 就是最终统一。
一致性模型有什么用
下面介绍了这么多一致性模型,咱们理解到越强的一致性他的约束条件就越多,如果咱们实现的话老本那么也就会越大。能够看见 ZK 如果想实现齐全的线性一致性,那么他就须要随时都调用 sync()去进行同步数据。
再咱们实在的场景中咱们数据库的主从复制模型(通过 binlog 复制也是程序一致性),从库的很大作用就是为了缓解主库的读压力,如果咱们想自觉的达到线性化一致性,那么就必须去拜访主库,这样咱们的从库的意义就微不足道了。
所以依据不同的零碎的模型,不同的业务要求,咱们对于一致性的要求是不同的,所以咱们理解这些一致性的模型是有很多必要的。
总结
这篇文章次要是介绍了什么是一致性,包含很多一致性模型,这里少讲了两个一致性事务一致性和利用一致性,有趣味的能够浏览分布式事务。还有一个值得一提的是,谈到一致性其实就离不开共识,因为当数据正本有多个的时候,到底抉择谁,如何抉择才是正确的,这个有趣味的同学能够自行查阅一些材料,比方 Raft,Paxos 和 Zab 等。
最初也再给大家几个问题:
- ZK 到底是一致性模型?
- Mysql 主从是什么一致性模型?
- Mysql 主主是什么一致性模型?
- 你罕用的一致性模型是什么?
参考文档:
- 如何了解 Zookeeper 的程序一致性:https://blog.csdn.net/cadem/article/details/80359270
- How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs,Lamprot
- Operational Characterization of
Weak Memory Consistency Models:https://mp.weixin.qq.com/s/gg4q_53eiHCI3OUWzN7eWg - Designing Data-Intensive Applications, Martin Kleppman
本文由 mdnice 多平台公布