目录
前言
我们分析下库存和订单会导致的问题
- 库存数据不一致
- 事务性的问题:是新建订单表,还是先扣减库存,无论哪个先都存在事务性的问题
- 使用分布式事务解决
- 业务下单但是用户不支付
- 支付成功之后扣减库存,用户体验很差不推荐
- 订单超时,库存归还,我们一般采用这种方案解决
- 事务性的问题:是新建订单表,还是先扣减库存,无论哪个先都存在事务性的问题
一、事务ACID
- 事务概念:事务就是用户定义的一系列数据库操作,这些操作可以视为一个完成的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元
- 为什么存在事务
- 失败后,可以回到开始位置
- 没都成功之前,别的用户(进程、会话)是不能看到操作内的数据修改的
- 事务四大特征
- 原子性(Atomicity):功能不可再分,要么全部成功,要么全部失败
- 一致性(Consistency):
- 事务的一致性要求事务必须满足数据库的完整性约束,且事务执行完毕后会将数据库由一个一致性的状态变为另一个一致性的状态
- 事务的一致性与原子性是密不可分的,如银行转账的例子 A账户向B账户转1000元钱,首先A账户减去1000元钱,然后B账户增加1000元钱,这两动作是一个整体,失去任何一个操作数据的一致性状态都会遭到破坏,所以这两个动作是一个整体,要么全部操作,要么都不执行,可见事务的一致性与原子性息息相关
- 【一致性关注的是状态,原子性关注的是功能;上述的转账状态我们可以分为3个状态:A未扣钱,B未收到钱;A已扣钱,B未收到钱;A已扣钱,B已收到钱; —— 一致性这里关注的是可见性,也就是中间红色的状态对外不可见,只有最初状态和最终状态对外可见】
- 隔离性(Isolation):事务的隔离性要求事务之间是彼此独立的,隔离的。及一个事务的执行不可以被其他事务干扰。具体到操作是指一个事务的操作必须在一个事务commit之后才可以进行操作。多事务并发执行时,相当于将并发事务变成串行事务,顺序执行,如同串行调度般的执行事务
- 持久性(Durability):事物的持续性也称持久性,是指一个事务一旦提交,它对数据库的改变将是永久性的,因为数据刷进了物理磁盘了,其他操作将不会对它产生任何影响
- 分布式事务:
- 分布式事务顾名思义就是要在分布式系统中实现事务,它其实是由多个本地事务组合而成;
- 对于分布式事务而言几乎满足不了ACID,其实对于单机事务而言大部分情况下也没有满足ACID,不然怎么会有四种隔离级别;所以更别说分布在不同数据库或者不同应用上的分布式事务了
- 本质上来说,分布式事务就是为了保证不同数据库的数据一致性
- 分布式系统的数据不一致
- 网络问题(最常见):硬件故障、网络抖动、网络拥塞
- 没有发送出去
- 发送出去了,没有返回,导致以为出错了
- 程序出错
- 代码异常
- 宕机:断电、系统问题(磁盘满了、电脑损坏等)
- 网络问题(最常见):硬件故障、网络抖动、网络拥塞
二、CAP理论
CAP理论是分布式系统的理论基石
1 - CAP理论
- 一致性(Consistency):
- 一致性指 “all nodes see the same data at the same time”,即更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致
- 一致性的问题在并发系统不可避免,对于客户端来说,一致性指的是并发访问时更新过的数据如何获取的问题;
- 从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致
- 可用性(Availability):
- 可用性指 “Reads and writes always succeed”,即服务一直可用,而且是正常响应时间
- 好的可用性是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况
- 分区容错性(Partition tolerance):
- 分区容错性指 “the system continues to operate despite arbitrary message loss or failure of part of the system”,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务
- 分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的整体;比如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,对于用户而言没有什么体验上的影响
2 - CAP权衡
通过 CAP 理论,我们知道无法同时满足一致性、可用性和分区容错性这三个特性;
所以只有三种组合情况:CA、CP、AP
孰优孰略,没有定论,只能根据场景定夺,适合的才是最好的
- CP策略:对数据一致性要求比较高的,如No SQL、Mongo DB、HBase、Redis
- 对于涉及到钱财这样不能有一丝让步的场景,C 必须保证
- AP策略:如No SQL、Coach DB、Cassandra、DynamoDB
- CA策略:单机的数据库,如单机的My SQL,那就没有P的需求了
三、BASE理论
实际开发中,我们会使用BASE理论,而不会使用CAP理论;
因为对我们来说放弃一致性或者放弃可用性,都是不可接受的
分布式系统中的一致性是弱一致性,单体数据库mysql的一致性是强一致性
分布式系统中是无法做到强一致性的
总结一句话:CAP告诉我们想要同时满足C、A、P就是做梦,BASE才是最终的归宿
1 - BASE理论
- BASE理论概念
- BASE 理论是对 CAP 理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)
- BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency)
- 基本可用(Basically Available)
- 基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用
- 电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现
- 降级页面:提示用户系统繁忙类似的页面
- 软状态( Soft State):软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mysql replication 的异步复制也是一种体现
- 最终一致性( Eventual Consistency):最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况
2 - BASE理论案例
- 转账案例的三个状态:A未扣钱,B未收到钱;A已扣钱,B未收到钱;A已扣钱,B已收到钱;
- BASE理论中
- 当前系统执行到A已扣钱,B未收到钱;时,B就来查询账户余额了,这时候系统可以提示B用户过一段时间后再来查询
- 而这个状态A已扣钱,B未收到钱;在BASE中可以理解为软状态
- 当过了一段时间,B的账号钱增加完成后,这时候才保证了一致性,这也就是BASE中的最终一致性
四、分布式事务解决方案
常见的分布式事务解决方案:
- 两阶段提交(2PC,Two-phase Commit)
- TCC补偿模式
- 基于本地消息表实现最终一致性
- 最大努力通知
- 基于可靠消息最终一致性方案
1 - 两阶段提交(2PC,Two-phase Commit)
- 2PC缺点:实现很简单,但是实际开发中不会使用,缺点太明显
- 性能问题:所有参与者资源和协调者资源都是被锁住的,只有当所有节点准备完成,事务协调者【订单服务】才会通知进行全局提交,参与者【库存服务、通知服务】进行本地事务提交后才会释放资源;这样的过程比较漫长,对性能影响比较大.
- 单节点故障:一旦协调者发生故障,参与者会一直阻塞下去;尤其是第二阶段,一旦协调者发生故障,所有参与都还处于锁定事务资源的状态种,而无法完成事务
2 - tcc分布式事务
- tcc事务:TCC事务其实是try-confirm-cancel的简称,将事务的步骤分为三步,属于柔性事务,因为2PC同步阻塞的缘故,就产生了效率高的TCC
- TCC可以解决跨库的数据一致性问题:常用于,电商库存扣减业务
- Try操作作为一阶段,负责资源的检查和预留
- Confirm操作作为二阶段提交操作,执行真正的业务
- Cancel是预留资源的取消
- 业务场景分析:一个订单支付后,我们需要如下的步骤
- ①.更改订单状态为“已支付”
- ②.扣减商品库存
- ③.给会员增加积分
- ④.创建销售出库单通知仓库发货
- TCC分布式事务总结:
- 实现起来太过复杂了,也没有成熟的开源库;TCC依然有上锁,也是无法支撑高并发
- 实现TCC需要修改原有的业务表结构,还需要修改对应的业务逻辑,成本太高
- 每个微服务都需要实现try、confirm、cancle等3个方法,开发成本太高,后期维护成本也很高
java有开源的seata分布式TCC框架,go也有go-seata
3 - 基本本地消息表的最终一致性
- 使用mq队列消息存在的问题
- 使用本地消息表解决方案
- 核心就是在本地增加了用户积分消息日志表;
- 同时增加定时任务触发,检测本地用户积分消息日志表是否有未发送的消息;
- 以此来保障最终数据一致性