分布式

分布式事务讲解之CAP,2PC,3PC,TCC

2023-03-30  本文已影响0人  上善若泪

学习此篇分布式事务前请先学习Spring事务讲解
点击了解Spring事务讲解

1 CAP

1.1 CAP原则

CAP原则又称CAP定理, 指的是在一个分布式系统中, Consistency(一致性) 、Availability(可用性) 、 Partition tolerance(分区容错性) , 三者不可兼得。

原则分类 详解
C
数据一致性(Consistency)
也叫做数据原子性系统在执行某项操作后仍然处于一致的状态。 在分布式系统中, 更新操作执行成功后所有的用户都应该读到最新的值,这样的系统被认为是具有强一致性的。 等同于所有节点访问同一份最新的数据副本
A
服务可用性(Availablity)
每一个操作总是能够在一定的时间内返回结果, 这里需要注意的是一定时间内返回结果。 一定时间内指的是,在可以容忍的范围内返回结果, 结果可以是成功或者是失败
P
分区容错性(Partition-torlerance)
在网络分区的情况下, 被分隔的节点仍能正常对外提供服务(分布式集群, 数据被分布存储在不同的服务器上, 无论什么情况, 服务器都能正常被访问)

分区容错性重点讲解:一个分布式系统里面,节点组成的网络本来应该是连通的。然而可能因为一些故障,使得有些节点之间不连通了,整个网络就分成了几块区域。数据就散布在了这些不连通的区域中。这就叫分区。当一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就访问不到这个数据了。这是分区就是无法容忍的。提高分区容忍性的办法就是一个数据项复制到多个节点上,那么出现分区之后,这一数据项就可能分布到各个区里。容忍性就提高了。然而,要把数据复制到多个节点,就会带来一致性的问题,就是多个节点上面的数据可能是不一致的。要保证一致,每次写操作就都要等待全部节点写成功,而这等待又会带来可用性的问题。
总的来说就是,数据存在的节点越多,分区容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更新所有节点数据所需要的时间就越长,可用性就会降低

1.1.1 数据一致性

数据一致性的种类:

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

最终一致性
不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。
最终两个字用得很微妙,因为从写入主库到反映至从库之间的延迟,可能仅仅是几分之一秒,也可能是几个小时
简单说,就是在一段时间后,节点间的数据会最终达到一致状态

1.1.2 图示讲解

让我们来考虑一个非常简单的分布式系统,它由两台服务器G1和G2组成;这两台服务器都存储了同一个变量v,v的初始值为v0;G1和G2互相之间能够通信,并且也能与外部的客户端通信;我们的分布式系统的架构图如下图所示:


image.png

一个简单的分布式系统

客户端可以向任何服务器发出读写请求。服务器当接收到请求之后,将根据请求执行一些计算,然后把请求结果返回给客户端。譬如,下图是一个写请求的例子:

客户端发起写请求


image.png

接着,下图是一个读请求的例子
客户端发起读请求


image.png

现在我们的分布式系统建立起来了,下面我们就来回顾一下分布式系统的可用性、一致性以及分区容错性的含义。

1.1.2.1 一致性

在一个一致性的系统中,客户端向任何服务器发起一个写请求,将一个值写入服务器并得到响应,那么之后向任何服务器发起读请求,都必须读取到这个值(或者更加新的值)。

下图是一个不一致的分布式系统的例子:


image.png

客户端向G1发起写请求,将v的值更新为v1且得到G1的确认响应;当向G2发起读v的请求时,读取到的却是旧的值v0,与期待的v1不一致。

下图一致的分布式系统的例子:


image.png

在这个系统中,G1在将确认响应返回给客户端之前,会先把v的新值复制给G2,这样,当客户端从G2读取v的值时就能读取到最新的值v1

1.1.2.2 可用性

在一个可用的分布式系统中,客户端向其中一个服务器发起一个请求且该服务器未崩溃,那么这个服务器最终必须响应客户端的请求。

1.1.2.3 分区容错性

服务器G1和G2之间互相发送的任意消息都可能丢失。如果所有的消息都丢失了,那么我们的系统就变成了下图这样:


image.png

为了满足分区容错性,我们的系统在任意的网络分区情况下都必须正常的工作

1.2 CAP如何舍弃

定律: 任何分布式系统只可同时满足二点,没法三者兼顾,对于 分布式数据系统,分区容忍性是基本要求,否则就失去了价值

三者择其二 分析
CA, 放弃 P 如果想避免分区容错性问题的发生, 一种做法是将所有的数据(与事务相关的)都放在一台机器上。 虽然无法 100%保证系统不会出错, 单不会碰到由分区带来的负面效果。 当然这个选择会严重的影响系统的扩展性
CP, 放弃 A 相对于放弃"分区容错性"来说, 其反面就是放弃可用性。一旦遇到分区容错故障, 那么受到影响的服务需要等待一定时间, 因此在等待时间内系统无法对外提供服务
AP, 放弃 C 这里所说的放弃一致性, 并不是完全放弃数据一致性,而是放弃数据的强一致性, 而保留数据的最终一致性。 以网络购物为例, 对只剩下一件库存的商品, 如果同时接受了两个订单, 那么较晚的订单将被告知商品告罄

1.3 eureka与zookeeper区别

对比项 Zookeeper Eureka
CAP CP AP
Dubbo 集成 已支持 -
Spring Cloud 集成 已支持 已支持
kv 服务 支持 - ZK 支持数据存储,eureka不支持
使用接口(多语言能力) 提供客户端 http 多语言 ZK的跨语言支持比较弱
watch 支持 支持 支持 什么是Watch 支持?就是客户单监听服务端的变化情况。zk 通过订阅监听来实现eureka 通过轮询的方式来实现
集群监控 - metrics metrics,运维者可以收集并报警这些度量信息达到监控目的

1.4 CAP对应的模型和应用

1.4.1 CA without P

理论上放弃P(分区容错性),则C(强一致性)和A(可用性)是可以保证的。实际上分区是不可避免的,严格上CA指的是允许分区后各子系统依然保持CA。

CA模型的常见应用:

1.4.2 CP without A

放弃A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。

CP模型的常见应用:

1.4.3 AP wihtout C

要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。

AP模型常见应用:

1.4.4 常见注册中心

举个大家更熟悉的例子,像我们熟悉的注册中心ZooKeeperEurekaNacos中:

1.5 BASE理论

BASE(Basically Available、Soft state、Eventual consistency)是基于CAP理论逐步演化而来的,核心思想是即便不能达到强一致性(Strong consistency),也可以根据应用特点采用适当的方式来达到最终一致性(Eventual consistency)的效果。
权衡了可用性一致性而提出的理论,相当于满足PA的情况(并没有完全舍弃C,只是舍弃强一致性,保留了最终一致性

image.png

BASE的主要含义:

2 分布式事务

现在实现分布式事务的设计方案应该有3种,分别就是二阶段提交、三阶段提交和TCC
他们都有2种重要的角色 事务协调者参与者,也就是各个服务

2.1 二阶段提交(2PC)

两阶段提交的思路可以概括为:
参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情况决定各参与者是否要提交操作还是回滚操作。

image.png

2.1.1 准备阶段

准备阶段:协调者(事务管理器)要求每个涉及到事务的数据库参与者 预提交(precommit)此操作,并反映是否可以提交

根据上面的UML图来看
1.3反馈准备提交或回滚 存在多种情况:

2.1.2. 提交阶段

提交阶段:协调者(事务管理器)要求每个数据库参与者提交数据或者回滚数据
根据上面的UML图来看

2.1.3 两阶段优缺点

优点:尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持。

缺点:

2.2 三阶段提交(3PC)

image.png

2.2.1 预判断阶段

预判断:协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应
如上图所示,1.2反馈情况

2.2.2 准备提交阶段

准备提交:协调者根据参与者在预判断阶段的响应判断是否执行事务还是中断事务,参与者执行完操作之后返回ACK响应,同时开始等待最终指令。
如上图所示

2.2.3 提交阶段

提交阶段:协调者根据参与者在准备提交阶段的响应判断是否执行事务还是中断事务:

如上图所示

为什么第三阶段等待超时就会自动提交呢?
因为经过了前面两阶段的判断,第三阶段可以提交的概率会大于回滚的概率

2.2.4 三阶段/二阶段差异

三阶段的参与者是有超时机制的,等待请求超时会进行事务中断,或事务提交
而二阶段不会超时,只会阻塞
可以看出,三阶段提交解决的只是两阶段提交中单体故障和同步阻塞的问题,因为加入了超时机制,这里的超时的机制作用于 准备提交阶段提交阶段。如果等待 准备提交请求 超时,参与者直接回到准备阶段之前。如果等到提交请求超时,那参与者就会提交事务了

注意:无论是2PC还是3PC都不能保证分布式系统中的数据100%一致

2.3 补偿提交(TCC)

2.3.1 定义

TCC(Try Confirm Cancel) ,是两阶段提交的一个变种,针对每个操作,都需要有一个其对应的确认取消操作,当操作成功时调用确认操作,当操作失败时调用取消操作,类似于二阶段提交,只不过是这里的提交回滚是针对业务上的,所以基于TCC实现的分布式事务也可以看做是对业务的一种补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。

TCC(Try-Confirm-Cancel)包括三段流程:

TCC 是业务层面的分布式事务,保证最终一致性,不会一直持有资源的锁。

2.3.2 操作

数据库表需要存多两个字段可更新数冻结数,将各个服务的事务执行分成3个步骤

如果是 confirmcancel出错了,一般会去重复执行,因为过了try,可以认为confirm是一定可以执行成功的,除非重复执行次数达到阈值,就落地成日志,让人工处理

image.png

注意:这里事务回滚的方式不像我们认为的那样 — 数据库直接给我们处理好
而是通过cancel将数据补回去,所以TCC也叫补偿机制

2.4 分布式事务总结

二阶段提交三阶段提交TCC分别是三种实现分布式事务的方案
至于具体的实现框架:二阶段有mysql的XA事务,TCC有seata、tcc-transaction
我们看TCC会涉及到服务与服务之间的接口调用,因为网络问题,极有可能出现重复调用的情况,所以【confirm】【cancel】这些接口应该要实现幂等
当然服务间的通信除了通过【同步的rpc】,也可以通过【异步的MQ】来实现,所以引出了接下来的基于MQ最终一致性方案

2.5 分布式锁

点击了解Zookeeper分布式锁
点击了解Redis分布式锁

上一篇 下一篇

猜你喜欢

热点阅读