基于可靠消息最终一致性的方案
• 业务处理服务在业务事务提交前,向实时消息服务请求发送消息,实时消息服务只记录消息数据,而不真正发送。业务处 理服务在业务事务提交后,向实时消息服务确认发送。只有在得到确认发送指令后,实时消息服务才真正发送
• 业务处理服务在业务事务回滚后,向实时消息服务取消发送。消息状态确认系统定期找到未确认发送或回滚发送的消息, 向业务处理服务询问消息状态,业务处理服务根据消息ID或消息内容确定该消息是否有效 • 被动方的处理结果不影响主动方的处理结果, 被动方的消息处理操作是幂等操作 • 一次消息发送需要两次请求,业务处理服务需实现消息状态回查接口设计图:
实现步骤: 1 .主动方(订单服务)在业务事务提交前,向实时消息服务请求发送消息,实时消息服务只记 录消息数据,而不真正发送。只将消息保存到DB,状态status为等待确认(WATING_CONFORM)。[步骤①,步驟a发送到mq的步骤还未执行,目前只是预发送(保存消息到DB)]2 .主动方执行具体的业务(比如操作订单相关的逻辑,步驟②),如果没有问题,调用消息服务,发送消息到mq,并且更新消息表为执行中状态(SENDING)[步骤③]
3 . 消息服端监听到消息后,调用被动方(会计服务)业务接口(比如操作会计凭证),如果成功(步骤d),调用消息服务确认系统,删除存储的消息[步骤e]
在步骤f有个消息恢复系统,主要处理两种异常情况:
i: 处理步驟②,执行具体业异常或者超时时,此时消息没有发送到MQ,且DB中存储的消息状态还是WATING_CONFORM,消息恢复子系统将这部分的数据拿出来重新发送, 此时需要注意,判断幂等性,因为存在执行步驟②【比如操作订单表】成功了,只是超时了,这个时间就需要判断订单是不是已经成功了,如果成功了就确认并发送消息,否则 直接删除这条消息(因为肯定是订单业务失败了,会回滚) ii:处理3中,调用被动方业务失败的情况,此时失败,就不会调用消息服务的确认系统,消息还存储在DB中,此时状态为SENDING,通过消息恢复系统,将这部分的数据重新发送MQ【注意有最多发送次数,超过时,直接设置该消息死亡状态】异常处理情况:
1.主动方预发送消息(存储DB)[步骤①] ,然后执行具体业务时(处理成功的情况),超时导致异常,此时步骤③没有执行,这时会通过消息恢复子系统重新处理(重发消息到mq,更改DB状态SENDING) 如果业务执行失败的情况,会通过消息恢复子系统直接删除DB里的消息。[因为异常导致回滚,整个业务都是失败的] 2. mq宕机,会通关消息回复子系统重发消息 3. 消息服务端监听后执行被动方业务失败或者超时,此时会通关消息回复子系统重发消息
目前自己搭建了一个环境,是开源的项目 reliable-message(提供服务) + reliable-message-samples(消费业务)这两个项目组成了一个 中间消息服务
项目开源可在git 下载