170. MQ本地消息表模式是如何保障分布式最终一致性的

一、 什么是事务消息?

事务消息是投递消息的一种方式,可以确保业务执行成功,消息一定会投递成功。

需要在业务本地库创建一个消息表(t_msg)

create table if not exists t_msg
(
    id              varchar(32) not null primary key comment '消息id',
    body_json       text        not null comment '消息体,json格式',
    status          smallint    not null default 0 comment '消息状态,0:待投递到mq,1:投递成功,2:投递失败',
    fail_msg        text comment 'status=2 时,记录消息投递失败的原因',
    fail_count      int         not null default 0 comment '已投递失败次数',
    send_retry      smallint    not null default 1 comment '投递MQ失败了,是否还需要重试?1:是,0:否',
    next_retry_time datetime comment '投递失败后,下次重试时间',
    create_time     datetime comment '创建时间',
    update_time     datetime comment '最近更新时间',
    key idx_status (status)
) comment '本地消息表'

事务消息投递的过程

  • step1:开启本地事务
  • step2:执行本地业务
  • step3:消息表t_msg写入记录,status为0(待投递到MQ)
  • step4:提交本地事务
  • step5:若事务提交成功,则投递消息到MQ,然后将t_msg中的status置为1(投递成功);本地事务失败的情况不用考虑,因为事务回滚了,此时消息记录也没有写到db的t_msg表中

异常情况

step5失败了,其他步骤都成功,此时业务执行成功,但是消息投递失败了,此时需要有个job来进行补偿,对于投递失败的消息进行重试。

消息投递补偿job

这个job负责从本地t_msg表中查询出状态为0记录或者失败需要重试的记录,然后进行重新投递到MQ。

对于投递失败的,采用衰减的方式进行重试,比如第1次失败了,则10秒后,继续重试,若还是失败,则再过20秒,再次重试,需要设置一个最大重试次数,最终还是投递失败,则需要告警+人工干预。

二、具体示例

用户下单后,我们需要通过MQ通知库存系统,库存系统扣减库存,如下:
在这里插入图片描述
上诉业务流程因为跨数据库,跨系统,所以很难直接保证事务性,此时就需要用到本地事务表了,如下:
在这里插入图片描述
说明:

  1. 用户下单后,不仅要插入记录到订单表,还需要插入一条消息记录到消息表,这两条记录因为是在同一个库,所以是可以直接用DB框架保证事务性的。
  2. 提交事务后,发送MQ,库存系统消费消息,更新库存记录,而后发送消息,订单系统消费到消息后,更新订单消息为处理完毕。

异常情况

  • 订单系统发的消息失败了,或者发送成功后,但是丢失或者库存系统消费失败了
  • 库存系统消费成功,但是发消息通知订单系统时失败了

无论是上面哪种情况,都会因为订单消息表的记录为正在处理,有定时任务扫描重发,因此会重试的,下游保证幂等即可。该方式可保证最终一致性。

上表解释:

  • 消息编号:需要保证唯一性,比如雪花算法生成ID
  • 订单编号:标识该消息是针对哪条订单的
  • 消息内容:用于重试发送等
  • 消息状态:跟踪消息处理进度,以及重试
  • 创建时间:还应该有更新时间等
  • 其余字段:重试次数,下次重试时间,是否还需要重试等

该方案所有可能的情况:
在这里插入图片描述

上面最后一条的 失败or指的是网络错误等,比如一个订单消息由于网络原因,重试到最大次数都发不出去,一直失败,,或者当前时间距离消息创建时间达到指定阈值,还处于正在发送状态,此时我们应该根据具体的业务处理,将消息和订单都作废,或者作废并报警,然后走人工处理流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值