介绍
RMQ(reliable-message-queue)是基于可靠消息的最终一致性的分布式事务解决方案。
中文文档
- 中文文档地址:https://www.showdoc.cc/rmq
源码地址:
RMQ对接示例:
- https://gitee.com/NuLiing/reliable-message-samples
- https://github.com/a327919006/reliable-message-samples
框架定位
- RMQ本身不生产消息队列,只是消息的搬运工。
- RMQ框架提供消息预发送、消息发送、消息确认、消息恢复、消息管理等功能,结合成熟的消息中间件,解决分布式事务,达到数据最终一致性。
流程说明
假设两个业务系统的两个业务AB需要在一个事务内处理。基于RMQ实现分布式事务流程图如下:
正常流程
-
在上层系统处理业务前,先向RMQ发送一条消息,RMQ收到后将该条消息持久化,但不向下投递。此时下层系统仍然不知道该条消息的存在。持久化成功后,向上层系统返回持久化成功。
-
上层系统收到应答后,执行业务A。业务A处理完成后,请求RMQ确认消息接口(异步)。该请求发出后,对上层系统而言,该事务的处理过程就结束了,此时它可以处理别的任务了。
为什么要异步请求确认消息接口?
(1) 假如使用同步请求,RMQ确认消息成功,已经把MQ消息发送给下层业务系统。但是响应时由于网络波动或其他原因抛出异常,使已经正常执行的业务A回滚,但是消息已经发出,下层业务已处理,就会造成数据不一致。
(2) 异步请求可以忽略确认消息请求的异常。假如确认请求异常,由消息确认子系统来处理,下文会介绍。
-
RMQ收到确认消息请求后,标记该消息为已确认,向下层系统投递该消息,从而执行业务B。
-
业务B执行完成后,下层系统调用RMQ确认消费消息,通知RMQ消息已经成功消费,RMQ会删除已成功消费的消息。
上述过程可以得出以下结论:
(1) RMQ扮演着分布式事务协调者的角色。
(2) 业务A完成后,到业务B完成之间,会存在一定的时间差。在这个时间差内,整个系统处于数据不一致的状态,但这短暂的不一致性是可以接受的,因为经过短暂的时间后,系统又可以保持数据一致性,满足BASE理论。
消息发送阶段异常流程
假设在消息投递给下层系统前,每一步都有可能因为网络或其他原因,发生异常。
- 如果异常不影响数据一致性,则无需处理。
- 如果异常影响数据一致性,则由RMQ的消息确认子系统,定时回查长时间未确认的消息。然后再根据业务处理结果投递或删除消息。如果回查请求异常(上层系统Down机或其他原因),则下次继续回查,直至上层系统返回明确结果。
异常情况 | 数据状态 | 数据一致性 | 处理 |
---|---|---|---|
预发送消息异常 | 消息未存储,业务未执行 | 一致 | 无需处理 |
消息持久化异常 | 消息未存储,业务未执行 | 一致 | 无需处理 |
返回应答异常 | 消息已存储,业务未执行 | 不一致 | 回查 |
执行业务异常 | 消息已存储,业务未执行 | 不一致 | 回查 |
确认发送消息异常 | 消息已存储(消息未确认),业务已执行 | 不一致 | 回查 |
标记消息已确认异常 | 消息已存储(消息未确认),业务已执行 | 不一致 | 回查 |
消息消费阶段异常流程
假设在消息投递给下层系统后,每一步都有可能因为网络或其他原因,发生异常。
- RMQ的消息恢复子系统,定时重发长时间未消费的消息。由于消息可能会重新投递,因此需要下层业务系统实现业务的幂等性。
- 消息恢复子系统重发消息有次数限制,超过一定次数,消息将会被标记为死亡,不再重发。可在消息管理子系统人工干预(删除或继续重发)。
架构图
节点角色说明
节点 | 角色说明 |
---|---|
消息服务子系统 | 暴露服务的服务提供方,业务服务实现(预发送消息、确认发送消息等) |
消息确认子系统 | 对于长时间未确认的消息,与上层业务系统确认消息是否发送 |
消息恢复子系统 | 对于长时间未消费的消息,重新发送消息给下层业务系统 |
消息管理子系统 | 消息可视化管理后台,消息队列配置、消息查看、重发、删除等 |
消息中间件 | 提供消息队列功能,ActiveMQ、RocketMQ等 |