通知型分布式事务
一、基于RocketMQ的事务消息方案
既然写到了分布式事务,而且之前也写过RocketMQ的原理,今天就在重复一下基于RocketMQ的事务消息方案
整体实现流程
- MQ生产者发送事务消息到MQ Broker中,此时MQ Broker把消息状态标记为(Prepared),此时这条消息,MQ消费者是无法消费的。
- MQ Broker回应MQ生产者,消息发送成功,表示MQ Broker已经接收到了消息并且保存成功。
- MQ 生产者此时开始执行本地事务
- MQ 生产者本地事务执行成功后自动向MQ Broker发送一个Commit消息,MQ Broker收到该消息后把第一步发送的那条消息标记为“可消费”,此时MQ 消费者可以正常收到这条消息进行处理。
- MQ消费者消费完这条消息后,向MQ Broker发送一个ACK表示成功消费,否则MQ Broker会不断重试。
- 如果MQ 生产者执行本地事务的过程中,MQ生产者宕机或者一直没有发送commit给到MQBroker,MQ Server将会不停的回查,询问同组的其他 Producer来获取事务执行状态。MQServer会根据事务回查结果来决定是否投递消息
RocketMQ事务消息的设计
- 主要是解决Producer端发送消息和本地事务执行结果的原子性问题,因此RocketMQ的设计中Broker和Producer端提供了双向通信的能力,使得Broker天生可以作为一个事务协调者。
- RocketMQ本身提供的存储机制未事务消息提供了持久化的能力。
- RocketMQ的高可用机制以及可靠性消息设计能力,为事务消息在系统发生异常时仍然能够保证消息的成功投递。
因此它的实现思想其实就是本地消息表的实现思路,只不过本地消息表移动到了MQ的内部,最终解决Producer端的消息发送和本地事务的原子性问题
二、RocketMQ事务消息对比本地消息表
RocketMQ事务消息:
- RocketMQ支持半消息机制或者类似特性,在重复投递上具有比较好的去重处理;
- 具有比较大的业务侵入性,需要业务方进行改造,提供对应的本地操作成功的回查功能;
DB本地消息表:
- 使用了数据库来存储事务消息,降低了对MQ的要求,但是增加了存储成本;
3、最大努力通知
最大努力通知方案的目标,就是发起通知方通过一定的机制,最大努力将业务处理结果通知到接收方。如果失败就衰减重试(需要幂等),并提供回查或者校验接口。本质是通过引入定期校验机制实现最终一致性,对业务的侵入性较低,适合于对最终一致性敏感度比较低、业务链路较短的场景。
特点
- 用到的服务模式:可查询操作、幂等操作;
- 被动方的处理结果不影响主动方的处理结果;
- 适用于对业务最终一致性的时间敏感度低的系统;
- 适合跨企业的系统间的操作,或者企业内部比较独立的系统间的操作。
幂等性保障
幂等性,就是重复调用多次产生的业务结果与调用一次产生的业务结果相同;
- 数据库唯一约束实现幂等
- 本地消息表生成唯一id(MD5)实现唯一约束
- 通过tokenid的方式去识别每次请求判断是否重复
- redis中的setNX
- 状态机幂等性