您好,登录后才能下订单哦!
本篇内容主要讲解“ACID、CAP、BASE的概念是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“ACID、CAP、BASE的概念是什么”吧!
1 案例背景
用户在电商网站购买了一件衣服,在支付成功后,支付系统需要将订单状态改为支付完成。需要注意支付结果和订单结果需要保持一致,不能出现支付成功后,订单状态却修改失败类似情况,否则用户就会很疑惑:明明支付成功了订单却是待支付状态。
对于这种要么同时成功,要么同时失败的场景,最容易想到的是使用事务。我们假设支付表和订单表属于同一个数据库。
这种场景代码实现并不难,我们只要利用数据库事务特性,就可以保证两张数据表要么同时成功,要么同时失败:
public class PayServiceImpl implements PayService { @Transactional public void pay() { updatePayInfo(); updateOrderInfo(); }}
但是在分布式场景中可没有这么简单。在分布式场景中订单是由订单团队维护,支付是由支付团队维护,所以订单系统和支付系统根本是两个系统,分别部署在不同服务器,分别提供服务,更不可能使用一个数据库:
所以在分布式场景中上述代码已经不适用了,我们需要新方案。在谈具体方案之前我们需要讲解一些理论知识。
2 理论知识
2.1 ACID
传统数据事务具有四大特性:原子性,一致性,隔离性,持久性,这些特性首字母组合在一起简称ACID特性。
原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)
(1) 原子性
一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中一部分操作
(2) 一致性
数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,如果这些事务有一部分修改已经写入数据库,那么数据库就处在不一致状态,这种情况不能被允许
(3) 隔离性
事务之间相互隔离,一个事务执行不能被其它事务干扰
(4) 持久性
当事务执行成功后,对数据库的修改将会永远保留在数据库。即使数据库出现故障,只要数据库能够重新启动,一定可以恢复到事务成功结束状态
在上述电商系统同一个数据库场景,正是使用了ACID这些特性才能达到我们预期业务要求。但是在分布式场景中就不再适用了,而且在分布式场景中解决分布式事务问题并不容易,这就引出了下一个概念:CAP理论。
2.2 CAP
1998年加州大学计算机科学家Eric Brewer提出分布式系统有三个指标,这三个指标首字母组合在一起称为CAP理论。
一致性(Consistency)可用性(Availability)分区容错性(Partition tolerance)
(1) 分区容错性
在分布式系统中不同节点(服务器)一般部署在不同子网络中,每一个子网络被称为一个区,不同子网络在网络通信时可能会失败,我们需要接受这种情况
(2) 可用性
只要收到用户请求,服务器就必须给出响应,用户在访问数据时必须得到及时响应
(3) 一致性
在分布式系统中同一个数据可能在不同节点保存多份,当更新操作成功并返回客户端完成后,所有节点(服务器)在同一时间数据必须完全一致
但是CAP理论三个指标无法同时满足,我们需要证明这个命题。我分析了很多证明文章,认为反证法这种方法比较清晰。下面我使用反证法证明这个命题:
假设CAP都满足则一定满足C假设CAP都满足则一定满足P因为满足C则节点间数据传递不能有网络故障第三点与第二点矛盾,证明完毕
我们看到在分布式实践中CAP理论有点不够用了,这里我们就要引出下一个概念:BASE理论,这是众多分布式实践的指导理论。
2.3 BASE
BASE理论扩展自CAP理论,核心思想是既然无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当方式来使系统达到最终一致性,这个理论也是我们分布式事务方案的理论基础。BASE由三个短语组成:
基本可用(Basically Available)柔性状态(Soft State)最终一致(Eventually Consistency)
(1) 基本可用
当分布式系统发生故障时,允许损失部分系统可用性。例如电商系统在大促无法承受流量洪峰时,可能会将用户引导至降级页面,或者触发服务熔断,保证大部分用户可用
(2) 柔性状态
CAP理论一致性这个指标不允许出现中间状态,所有状态必须保证强一致性。但是柔性状态可以允许短时间节点间不一致状态出现
(3) 最终一致
既然节点间存在短时间不一致状态,那么在一段时间后通过业务手段,节点间状态需要最终达成一致。分布式实践中不追求强一致性,而追求最终一致性
3 事务性消息实践
分布式事务解决方案有很多,例如两阶段提交,TCC,事务性消息。我在分布式事务实践中最常使用事务性消息。首先我们用一个生活实例来描述什么是事务性消息。
小明去面馆吃面条,有很多人在排队。小明付过钱之后就找空位坐了下来,因为空位是随机分布的,那么服务员怎么保证可以把面条准确送到小明的桌上?答案是凭借小明手上的取餐小票。取餐小票是小明购物凭证和消费依据,有了小票就不用担心吃不到面条。取餐小票就是事务性消息。
本章节就把事务性消息这个方案讲透,还是使用订单系统和支付系统这个案例。
3.1 场景一
假设你是支付团队成员,订单系统由订单团队维护。订单团队愿意配合你们做系统改造,那么可以使用如下事务性消息架构图:
根据这张图分析事务性消息如何工作:当用户支付成功后,支付系统将支付完成数据保存在数据库,并且在同一个事务中新增一条消息,状态是「待处理」。注意这个消息与支付数据保存具有强一致性,同时成功或者同时失败,我们称这种消息为事务性消息。
当保存成功事务性消息后,发送事务性消息进入消息队列。订单系统通过消息队列订阅到这个消息后,把对应订单状态设置为已支付,同时调用支付系统接口将这条消息设置为「已处理」,整个正向流程就结束了。
但是订单系统调用修改消息接口有可能失败,也就是虽然业务处理成功了,事务性消息状态依然是「待处理」,这时就需要定时补偿器发挥作用了。定时补偿器定时将之前一段时间,状态为「待处理」的消息再次发送至消息队列,由订单系统再次订阅处理,这需要订单系统保证幂等性。
分析到这里事务性消息工作原理已经讲清楚了,但是不能就此止步。我们还要继续分析一个问题:假设订单系统很长时间一直处理不成功,导致消息一直「待处理」怎么办?
出现这种原因可能是订单系统宕机了,那么补偿器一直频繁重试是没有结果的,所以我们要给消息重试一个阶梯时间:第一次不成功过5分钟重试,第二次不成功过15分钟重试,第三次不成功30分钟后重试,这样可以给订单系统恢复时间。
我们还要设置一个最大重试次数,假设重试十次后仍然不成功,那么系统要将消息设置为「已过期」,同时发送告警并进行人工干预。事务性消息场景一般不会像传统事务方式出现异常时发生回滚,而是通过重试继续进行链路,或者进行人工干预。
3.2 场景二
假设你是支付团队成员,订单系统由订单团队维护。订单系统只是通过暴露接口的方式对外进行交互,没有时间配合改造系统为监听消息模式。面对这种场景我们就需要对场景一架构图进行改造,但是核心思想不变。
我们根据这张图分析事务性消息如何工作:当用户支付成功后,保存支付业务数据和新增消息原理和场景一相同。当保存成功事务性消息后,直接调用处理订单业务接口,调用成功后将这条消息设置为「已处理」,整个正向流程就结束了。
当调用处理订单业务接口失败或者无响应,消息状态仍然为「待处理」。定时补偿器定时将之前一段时间,状态为「待处理」的消息再次调用处理订单业务接口,这需要订单系统保证幂等性。
如果订单系统没有保证幂等性,在再次调用处理订单业务接口时,需要先查询订单接口是否已经处理过,明确返回未处理时才进行调用,否则放弃本次补偿调用,等待再次重试,补偿重试策略与场景一相同。
4 RocketMQ
如果使用RocketMQ消息中间件,可以直接使用其事务消息机制,通过发送half消息、提交或回滚half消息、定时业务回查也可以实现最终一致性。
到此,相信大家对“ACID、CAP、BASE的概念是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。