一、前言
可靠消息最终一致性方案主要适用于消息数据能够独立存储:
-
能够降低系统之间耦合度
-
业务对数据一致性的时间敏感度高
此方案需要实现的服务模式:
-
可查询操作:提供查询自身事务状态的接口。
-
幂等操作:只要参数相同,无论调用多少次接口,都应该和第一次调用产生的结果相同。
那么什么时候回查?
事务发送端执行本地事务时(已经发送了 Half 消息了),这时候发送端宕机了或者超时了,就需要回查了。
(1)实现方案
实现方案有两种:
1.基于本地消息
-
优点:在业务应用中实现了消息的可靠性,减少了对消息中间件的依赖。
-
缺点:
-
绑定了具体的业务场景,耦合性太高,不可公用和扩展。
-
消息数据与业务数据在同一数据库,占用了业务系统的扩展。
-
消息数据可能会受到数据库并发性的影响。
2.基于消息队列中间件
-
优点:
-
消息数据能够独立存储,与具体的业务数据库解耦。
-
消息的并发性和吞吐量优于本地消息表方案。
-
缺点:
-
发送一次消息需要完成两次网络交互:1.消息的发送 ; 2. 消息的提交或回滚。
-
需要实现消息的回查接口,增加了开发成本。
(2)注意的问题
1、事务发送方本地事务与消息发送的原子性问题:
-
原因:执行本地事务和发送消息,要么都成功,要么都失败。
-
解决方案:通过消息确认服务本地事务执行成功。
// 原子性:事务 + 消息确认(回滚)
@Override
@Transactional(rollbackFor = Exception.class)
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object obj) {
try{
TxMessage txMessage = this.getTxMessage(msg);
// 1. 执行本地事务
orderService.submitOrderAndSaveTxNo(txMessage);
// 2. 提交事务
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e){
// 异常回滚事务
return RocketMQLocalTransactionState.ROLLBACK;
}
}
2、事务参与方接收消息的可靠性问题:
-
原因:由于服务器宕机、服务崩溃或网络异常等原因,导致事务参与方不能正常接收消息; 或者接收消息后处理事务的过程中发生异常,无法将结果正确回传到消息库中。
-
解决方案:通过消息恢复服务保证事务参与方的可靠性。
3、事务参与方接收消息的幂等性问题:
-
原因:可靠消息服务可能会多次向事务参与方发送消息
-
解决方案:需要具有幂等性,只要参数相同,无论调用多少次接口或方法,结果都相同。
C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址
另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以自行添加:Q群:720209036 点击加入~ 群文件共享
(3)实战
通过 RocketMQ 消息中间件实现可靠消息最终一致性分布式事务,模拟电商业务中的下单扣减库存场景。 涉及服务有:
-
订单服务
-
库存服务
整体流程如下:
-
第一步:订单服务向 RocketMQ 发送 Half 消息。
-
第二步:RocketMQ 向订单服务响应 Half 消息发送成功。
-
第三步:订单服务执行本地事务,向本地数据库中插入、更新、删除数据。
-
第四步:订单服务向 RocketMQ 发送提交事务或者回滚事务的消息。
-
第五步:如果库存服务未收到消息,或者执行事务失败,且 RocketMQ 未删除保存的消息数据ÿ