一致性模型
文章目录
一:重要的一致性模型(重要)
前面说到了CAP & BASE
CAP
一致性:任何时间点,在任意节点上看到的数据完全一致;BASE
一致性:数据只能从一个一致状态变化到另一个一致状态。
CAP
理论针对的是数据一致性,主要关注怎样维持多副本的一致性视图,即如何使多个节点上的数据,对外表现的和一份数据一样。
BASE
理论关注状态一致性,主要在于根据业务需求操作不同节点的数据时,最终实际执行结果和我们的观念一致,即分布式系统中的业务操作,执行完成后结果都在预期之内,而不是"部分成功、部分失败"这种预期之外的结果。
这两个一致性的定义,涵盖了分布式系统中的所有场景
建立在这两个定义的基础上,又存在三种较为重要的一致性模型,即强一致性、弱一致性、最终一致性,
这三个一致性模型,作用在数据一致性、状态一致性上的含义 并不相同
数据一致性案例
互联网大流量的背景下,为了保证服务可用性,通常会采用集群化模式部署,以此实现任意节点故障,都不会影响系统正常的对外服务能力
如上图所示,这是一个十分典型的高可用场景,采用集群式部署
当外部向系统写入一个值X
后,该值会被同步给集群内剩余两个节点,从而保保证所有节点的数据一致性,流量切至任意节点,都能确保看到的数据相同
状态一致性案例
为了尽可能提升系统吞吐量,也会将原本单个庞大的系统,拆分成多个子系统/微服务运行
一个业务需求由多个服务一起满足,多个服务之间通过远程调用来进行交互与通信
这是一个简化到极致的下单场景,只由创建订单、扣减库存两个动作组成,在分布式系统中,每一个下单请求都会执行这两步操作。
按照我们的观念,创建一笔订单后,相应的库存都会进行扣减,这样的结果才符合设想的预期,而这种符合我们预期的结果,则满足状态一致性的要求,毕竟整体数据的变化是一致的
1:强一致性模型
强一致性,又称原子一致性、线性一致性、严格一致性、实时一致性……
它是一种苛刻的一致性要求,这是实现难度最高、可用性最低、性能最差的一致性模型,先来看看数据的强一致性。
1.1:数据强一致性
当外部写入X
值在A
节点成功后,B、C
节点应该立即能看到此数据,只有这样才是满足强一致性要求的。
这个要求听起来没啥特别,但要注意,集群内各节点的数据同步工作,依靠网络完成,走网络需要时间成本
无论如何优化,A
和B、C
节点间都会存在短暂的不一致,而这就打破了“强一致性”的要求。
那该怎么做?在之前有提过,如果想要保证所有节点的数据强一致,那就在数据写入时下功夫,即X
写入A
节点后,并不代表X
写入成功,需要继续在B、C
节点写入成功后,才算数据写入完成,这样就能保证强一致性。
当然,这样还不够,对数据读取请求也得进行控制,如下:
当数据在A、B
节点写入完成、C
节点正在写入中,此时去C
读取数据会怎么样?
答案是看到X=1
这个旧值;当请求去A
读值,为了保证看到的数据相同,这时A
就不能返回X=2
这个新值,而是同样返回1
需设计类似于MVCC
这种多版本并发机制,这样才能保证所有节点的强一致性。
1.2:状态强一致性
前面说清楚了数据的强一致,接着来聊聊状态的强一致性,回到最开始给出的下单场景:
想要保证这个场景中的状态强一致,意味着需要保证创建订单、扣减库存操作一起完成
即订单服务创建订单后,不能立马将订单数据提交,必须等扣减库存成功才行。
如果扣减库存未完成,前面的订单数据就需要一直阻塞等待,也就是典型的XA
事务模式,在分布式场景中咋实现?
首先要引入独立的事务管理者,分布式事务对应的多个操作,会被视为一个“事务组”:
上述下单场景中,两个动作分别对应着两个子事务,在创建订单后,首先订单服务会向事务管理者中注册一个事务组,而后把创建订单的执行结果(成功或失败)提交给管理者;接着商品服务开始执行,执行完成后也会将结果加入到前面创建的事务组中。
两个子事务均已抵达事务管理者后,事务管理者会做统一的决断,当事务组所有子事务都执行成功后,才会真正向该组事务的参与者下发“提交事务”的信号,此时整组事务才会真正被提交。同理,只要一个子事务失败,整组事务都需要被回滚
上述方案中,在事务管理者没有下发最终处理结果之前,所有子事务都需要阻塞等待,从而保证状态的强一致性,整体数据一起从一个状态转变为另一个状态。
尽管这种方式能实现接近于ACID
原则的强一致性效果,可对应的代价是牺牲掉一定的可用性
一方面阻塞的事务会长时间占用着数据库连接不释放,另一方面则会延长接口响应时间,影响整体的性能。
2:弱一致性模型
与强一致截然相反,即:虽然我提供了一致性的支持,但系统可能会出现不一致的现象,对这种不一致的情况,我也不保证它最终会变成一致的结果。
这有点类似于Redis
提供的“弱事务机制”
Redis
虽然提供了事务相关的命令