消息中间件学习-摘抄( 二 )


上图是提供的保证MQ消息、DB事务一致性的方案 。
MQ消息、DB操作一致性方案:

消息中间件学习-摘抄

文章插图
1)发送消息到MQ服务器,此时消息状态为 。此消息为不可见 。
2)执行DB操作;DB执行成功 DB操作,DB执行失败 DB操作 。
3)如果DB执行成功,回复MQ服务器,将状态为;如果DB执行失败,回复MQ服务器,将状态改为 。注意此过程有可能失败 。
4)MQ内部提供一个名为“事务状态服务”的服务,此服务会检查事务消息的状态,如果发现消息未,则通过启动时注册的ener来回调业务系统,业务系统在方法中检查DB事务状态,如果成功,则回复,否则回复 。
说明:
上面以DB为例,其实此处可以是任何业务或者数据源 。
以上、、均是 jar提供的状态,在MQ服务器内部是一个数字 。
ener 是在消息的或者消息丢失的情况下才会回调(上图中灰色部分) 。这种消息丢失只存在于断网或者集群挂了的情况下 。当集群挂了,如果采用异步刷盘,存在1s内数据丢失风险,异步刷盘场景下保障事务没有意义 。所以如果要核心业务用解决分布式事务问题,建议选择同步刷盘模式 。
2. 多系统之间数据一致性(多方事务)
image.png
当需要保证多方(超过2方)的分布式一致性,上面的两方事务一致性(通过的事务性消息解决)已经无法支持 。这个时候需要引入TCC模式思想(Try--,不清楚的自行百度) 。
以上图交易系统为例:
1)交易系统创建订单(往DB插入一条记录),同时发送订单创建消息 。通过事务性消息保证一致性
2)接着执行完成订单所需的同步核心RPC服务(非核心的系统通过监听MQ消息自行处理,处理结果不会影响交易状态) 。执行成功更改订单状态,同时发送MQ消息 。
3)交易系统接受自己发送的订单创建消息,通过定时调度系统创建延时回滚任务(或者使用的重试功能,设置第二次发送时间为定时任务的延迟创建时间 。在非消息堵塞的情况下,消息第一次到达延迟为1ms左右,这时可能RPC还未执行完,订单状态还未设置为完成,第二次消费时间可以指定) 。延迟任务先通过查询订单状态判断订单是否完成,完成则不创建回滚任务,否则创建 。PS:多个RPC可以创建一个回滚任务,通过一个消费组接受一次消息就可以;也可以通过创建多个消费组,一个消息消费多次,每次消费创建一个RPC的回滚任务 。回滚任务失败,通过MQ的重发来重试 。
以上是交易系统和其他系统之间保持最终一致性的解决方案 。
3.案例分析
1) 单机环境下的事务示意图
如下为A给B转账的例子 。
步骤动作
锁定A的账户
锁定B的账户
检查A账户是否有1元
A的账户扣减1元
给B的账户加1元
解锁B的账户
解锁A的账户
以上过程在代码层面甚至可以简化到在一个事物中执行两条sql语句 。
2) 分布式环境下事务
和单机事务不同,A、B账户可能不在同一个DB中,此时无法像在单机情况下使用事物来实现 。此时可以通过一下方式实现,将转账操作分成两个操作 。
a) A账户
步骤动作
锁定A的账户
检查A账户是否有1元
A的账户扣减1元
解锁A的账户
b) MQ消息
A账户数据发生变化时,发送MQ消息,MQ服务器将消息推送给转账系统,转账系统来给B账号加钱 。
c) B账户
消息中间件学习-摘抄

文章插图
步骤动作
锁定B的账户
给B的账户加1元