一 什么是可靠消息最终一致性
事务发起方服务执行完本地事务后向消息中间件发送一条消息,消息中间件通知下游服务执行本地事务。
二 使用可靠消息最终一致性的前提
下游服务执行本地事务失败不会对上游服务造成影响。事务不要求强一致
三 使用可靠消息最终一致性必须要解决的问题
- 上游服务的本地事务与发送消息的原子性
上游服务的本地事务与发送消息给消息中间件必须同时成功或同时失败 - 下游服务必须能够从消息中间件接受到消息
消息中间件在不确认下游服务已接收消息时必须能够重发消息 - 下游服务处理消息的幂等性
下游服务必须解决处理消息的幂等性
四 RocketMQ事务消息方案
4.1 RocketMQ充当消息中间件如何解决上述问题
4.1.1 如何解决"上游服务的本地事务与发送消息的原子性"
发送使用带有事务的发送方法:RocketMQTemplate().sendMessageInTransaction()
- MQProducer 发送消息至 MQSever,MQSever 将消息置为Prepared(预备状态),这个事务 MQConsumer 是无法消费消息的。
- MQSever 回应 MQProducer 已接收到消息。
- MQProducer 执行本地事务并向 MQServer 发送commit或者rollback消息。
发消息应该嵌入到本地事务之中 - MQServer 接收到 MQProducer 的消息决定将之前的消息置为可消费还是置为失效。
- 若 MQServer 长时间未收到 MQProducer 的commit或者rollback,MQServer 会主动询问 MQProducer 事务执行结果。这叫事务回查。所以 MQProducer 应该实现供给事务回查的方法。
4.1.2 如何解决"下游服务必须能够从消息中间件接受到消息"
使用ack(消息确认机制),如果 MQConsumer 接收到 MQServer 的消息并且成功执行,MQConsumer 会给 MQServer 发送ack消息确认,否则 MQServer 会一直发送消息给 MQConsumer。
4.1.3 如何解决"下游服务处理消息的幂等性"
在 MQConsumer 消费消息之前先确认当前消息是否已经被消费过,编码解决(消费消息记录入库)。
五 总结
可靠消息最终一致性基于Base(基本可用软状态最终一致)理论将分布式事务解耦,使得同步的事务变为异步操作,避免了同步阻塞操作的影响,在对数据非强一致的情况下增加了吞吐量。