什么是分布式事务
如果我们在支付订单操作完毕之后我们需要通过我们的RPC远程调用操作我们的需要去操作我们的这个积分的数据(在多数据源的情况),那么如果说我们在积分操作完成,再去执行我们的这个支付服务的时候此时我们的这个支付服务已经报错了,但是我们的这个积分服务已经把事务提交了,那么这就是我们的这个分布式事务的问题
分布式事务的解决方案
1.我们在单体项目架构当中我们可以通过使用jta+atomikos的方式去解决我们的这个分布式事务
2.通过使用MQ的方式去解决,利用我的这个最终一致性来保持我的这个数据的相同
3.使用MQ解决分布式事务,采用事务消息
4.LCN采用LCN模式 加关闭链接(该技术已经淘汰)
5.我们可以通过alibaba的seata来解决分布式事务,已经成为了主流的,但是他的性能一般,他的响应时间是比较长的
6.在跨语言的时候我们可以通过使用MQ的方式采用我们的这个最终一致性来解决我们的这个分布式问题
2PC,3PC的应用场景
就是说我在我的这两个服务调用的时候我们可以使用seata来实现来解决我们的这个分布式事务
同时也可以使用LCN来进行解决分布式事务,底层主要是基于netty来解决的
使用LCN和seata来解决我的这个分布式事务的原理
比如说我的这个支付服务在调用了积分服务的时候如果说我的这个支付服务报错了,那么我的这个支付服务就会去向我的这个事务协调者(TM)申请说我的这个支付服务报错了,那么我的这个事务协调中就会把TM进行提交,需要我的这个积分服务去进行回滚,同样的如果说我的这个支付服务调用完我的这个积分服务之后没问题那么我就会去调用我的这个支付服务就会向我们的这个事务协调者(TM)说我这边没问题,那么我的这个事务提交者就会要我们的这个积分服务进行提交、
缺陷
如果我的这个事务在不提交和不会滚的情况下会发生什么问题?
如果说没有提交的话那么他就会触发我们的这个行锁机制
在我们的分布式架构当中如果说我们的这个事务协调者如果出宕机了那该如何去处理?
如果我的这个事务协调者如果说都宕机了,那么参与方会根据我们的这个设定的超时机制来 实现,如果事务协调者没有及时的与发送方发送提交或者是回滚则会直接认为是超时,回滚,后期就可以通过发起结果 采用定时任的形式来进行补偿
首先我们在一般的情况下我们的这个事务协调者他是搭建了集群的,如果说我的集群都 宕机了的话那么就会出现一下几种情况
场景一:我的这个支付功能成功,我的积分服务没有成功
运行的错误
那么我们会通过超时机制来给我们的这个消费者来进行相关的补偿的方式来进行
场景二:我的这个积分服务已经成功,但是支付功能没有成功
不允许的错误
如果使用setata的AT模式可能会出现脏读的问题
如何使用MQ解决分布式事务问题
1.生产者
作为生产者的话我们需要使用到的是一下几点:
ACK消息确认机制
同步异步的形式
方式1:通过使用confirm
方式2:事务消息
如果说生产者在消息投递失败的情况下,我们可以通过日志来把他记录下来,我们可以通过定时任务实现补偿 投递msg消息 同时也可以使用手动ACK
2.MQ服务器端:
需要将消息进行持久化,避免MQ在存入到消息的时候消息丢失,MQ服务器端在默认的情况下可能会出现队列的消息持久化的一个操作,持久到我的这个硬盘
刷盘操作严格意义上来说可以完全保证我们的这个消息不会被丢失或者是异步的话可能会出现消息丢失
3.消费者
3.1在我们的这个rabbitMQ的情况下:
必须要将我们的这个消息投递到我们的这个message的消息当中去
3.2在kafka的情况下:
不管是消息是否消费成功还是失败,该消息都会不会立即从mq服务端中移除,手动提交offset
如果消费者消费失败还是成功的情况下则MQ会采用间隔形式不断的重试
在重试的过程当中可能会出现我们的消息重复消费也就是消息幂等性问题
我们可以把这个新增的这个订单ID作为我数据库的这个主键ID来保证我的这个数据唯一性,如果说我的这个Messaage消息里面的ID和我的这个订单表中的消息一致的情况下那就新增失败嘛
如何解决Message消息的延迟问题
1.我们可以搭建MQ的消息集群消费,
2.我们的这个消息的批量消费
他的核心思想就是使用我们的在最终一致性
在该流程的情况下时候不需要去解决我们的消息顺序一致性的
谈谈分布式锁的引用场景
比如说我们的这个电商在高并发的情况下我们可以使用分布式锁的形式来进行库存锁住
当我们在使用双写一致性的时候我们可以使用分布式锁来锁住我们的这个redis和我们的这个Mysql数据库
分布式锁的实现方案
1.基于数据库的实现--Mysql行锁时实现
2.基于Zookeeper cp模式来实现
3.使用Redis setnx实现 AP模式
4.Redis框架Redission,RedisLock等等
要求 :保证一致性ZK实现分布式锁
要求:保证可用性redis实现分布式锁 比如说redis的红锁
使用zookeeper来实现分布式锁
使用我们的这个zookeeper我们需要去创建我们的这个临时节点,
但是我们在使用Zookeeper的时候节点路径不能重复保证唯一性 临时节点+事务通知
1.获取锁的方法
多个jvm同时在zk上创建同一个相同临时节点/lockPath
最终只能有一个jvm来标识获取锁成功能够正常执行业务逻辑,如果没有创建临时节点成功的jvm,则标识获取锁失败,获取锁失败之后可以不断重试策略,重试多次,获取锁失败之后当前的jvm就进入到阻塞状态
2.释放锁的方法
我们可以直接使用close的方法去释放我们当前的这个zk的方法
在删除了之后zk就会告诉其他的jvm就是说你们可以开启竞争的一个状态
3.被唤醒的方法
当我们的这个jvm的锁被释放了之后那么我们就会告诉其他的jvm说你们可以进入竞争状态了
zookeeper实现分布式锁的时候业务超时,一直不释放锁该如何处理?
如果说我们的这个@Trantsactional(rollbackFor = exception)的这个事务注解来解决我们这个事务报错的进行回滚的操作
解决方案
我们可以采用续命的设计来实现,续命多次如果业务还是没有执行完毕的情况下我们可以认为这个锁已经超时了,那么我们可以使用续命的方式来防止其他的jvm长时间的等待,业务代码讲全部进行回滚