黑马程序员技术交流社区
标题: 【黑马程序员济南】分布式事务 [打印本页]
作者: 小鲁哥哥 时间: 2018-1-5 14:02
标题: 【黑马程序员济南】分布式事务
本帖最后由 小鲁哥哥 于 2020-1-17 17:08 编辑
【黑马程序员济南】分布式事务
分布式事务:当我们进行操作的时候不是操作相同的数据库,那么事务的连接也就不一样。
这个时候要解决两个数据库的事务的原子性。那么就需要使用分布式事务。
方案一:如果使用同一个Spring容器管理了多个数据库,那么就可以使用Spring JTA解决分布式事务,这个只是数据库层面的一个分布式,服务并没有分布式。
方案二:如果使用的不同的Spring容器,就是说我们的项目是分布式。比如我们的serviceA要操作数据库A,serviceB操作数据库B,并且serviceA和serviceB在不同的子系统中,但是现在需要在serviceA中调用serviceB完成业务,那么如何解决两者之间分布式提交。
答:目前比较流行的解决方法是结合MQ消息中间件并且实现的事务最终一致性,这里采用rocketMQ消息提供的事务消息机制(准备提交-MQ确认可以接收-确认发送消息)可以保证本地事务和消息发送事务要么一起成功,要么一起失败,同时提供超时机制重复发送消息,并且可以解决消息重复的问题(记录消息id的方式,保证重复发生的消息的id与第一次发送的消息id一致),但是无法保证消息消费者端事务一定成功提交,这里一般需要在生产者消息发送成功之后记录一条事务消息到redis缓存中,redis缓存记录了消息事务的id还有消息事务的状态以及相关必要信息,如果消费者事务提交成功那么修改该消息在redis中的状态,如果消费者事务失败,redis状态将不能得到改变,那么我们就可以在后台从redis中得到失败的事务,然后再由人工进行处理,这样就可以保证事务的最终一致性。
案例说明:现我给你转账1000,那么我就应该扣1000,而你要加1000,但是扣款的服务在系统A的serviceA中,而加款的服务在系统B的serviceB中,这个时候在serviceA调用serviceB完成转账过程。事务执行过程
1). serviceA开始
2). RocketMq发送一条预处理消息发送给MQ消息队列一条Prepared消息。(成功则往下执行,不成功则事务失败。整个流程结束)
3). 执行ServiceA的本地事务,执行我的扣款操作。
4). 向redis中添加一条事务消息,采用hash来保存。Hash中的key是当前事务消息的id。Value保存了事务消息的状态,还有相关必要的数据。
5). 执行确认消息发送,确认消息发送面临的问题:消息可能发送不成功,这个时候RocketMQ提供超时机制,如果消息发送超时那么可以在尝试重新发送几次,超过指定次数,消息发送失败,事务回滚。如果消息发送成功,可能会面临消息重复发送的问题,那么采用日志记录已经被消费的消息的id,防止重复消费。这样就能保证消息发送和本地事务能够同时成功或者同时失败。如果消息发送成功那么扣款事务也一定提交,而不再考虑加款事务是否成功,因为后面就算加款事务没有成功,还有人工处理。
6). 消息成功发送之后,消费者接收到消息,成功提交事务之后,你的加款操作,修改redis中对应消息记录的状态。但是存在消息没有被消费者收到或者消费者事务失败的问题,这个时候人工处理根据redis中的事务消息,找到还没有成功的事务手动处理。保证事务的最终一致性。
7). 事务结束。
作者: 尹哈哈哈 时间: 2018-1-5 16:42
支持一下楼主
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |