写在前面:做供应链业务一年有余了,这一年里MQ帮我们解决了很多问题,在此做一些经验总结;另外,各个公司消息中间件提供的功能大同小异,最基础的推消息、下游异常重试机制应该是都具备的,本文所述也是建立在这样的能力基础上的~

场景一:削峰填谷,降低响应时间,下游异常自动重试、保证成功

举例:对库存模块而言,入库是一个增量操作,当通过了数据校验之后就理应执行成功,但入库操作常常伴有复杂的写库逻辑及乐观锁冲突,同步模型平均响应时间长,且并发条件下乐观锁冲突失败概率较大;这里就可以引入MQ,将写库操作异步处理,简要流程如下:
图片描述

需要注意的是:
1、如果有重复发消息地可能性,MQ下游需要做业务幂等,整条链路要有并发锁保护(redis实现并发悲观锁可参看文章:https://segmentfault.com/a/11...);
2、如果下游触发异常,中间件一般会自动重试(并发乐观锁冲突自动重试可解决,中间件一般会提供一直重试、重新入队、丢弃消息等模式,需根据具体场景选取,在此不再赘述);如果是非重试能够解决的异常,则需要再监控到异常后,人工介入跳过、修复、补偿;
3、示例情况是上游无写库,如果上游有写库,可能出现发消息与事务写库两个事件状态不一致的情况,一般会有三种情况:

(1)先事务写库,再发消息;当发消息失败时,写库事务已提交,无法回滚;
(2)先发消息,再事务写库;当写库失败时,消息已发送,无法回滚;
(3)写库事务中发消息,如果发消息失败,事务可以回滚,但如果发消息成功后,事务提交时失败(有这种可能),消息也无法回滚;

如果上游无法避免写库时,我们一般采用先事务写库,再发送消息,因为消息中间件作为基础服务,一般是可靠的,很小概率出现发消息失败;如果出现了,有两种处理方式:

(1)发消息失败,返回客户端失败,则需要脚本补偿,回滚上游写库;
(2)发消息失败,只报警,但返回客户端正常,则需要补偿消息;

场景二:异步处理,服务解耦
举例:每一次操作库存后都需要记录业务操作日志,每个Stock(库存服务)接口都需要在完成库存逻辑后,再调用Log(日志服务)记录操作日志;如果采用同步调用模型,Stock服务就与Log服务耦合,依赖于Log服务的实时响应结果,如果Log服务挂了,Stock服务也就挂了,这不是我们期望看到的;这里就可以引入MQ实现核心流程与非核心流程的解耦,简要流程如下:
图片描述

这样,上游只需依赖MQ,一般而言,相比下游服务,中间件是更可靠的;通过MQ的能力,如果下游出现问题,主流程不会阻塞,有更多的时间修复,且更易补偿;

场景三:多下游的发布订阅
举例:商品信息作为供应链基础数据,在几乎所有系统都有应用;如果商品信息变更,其他系统就需要接收变更信息,如何通知就是一个问题;同步通知模型会耦合所有下游服务,响应时间长,在增加或减少接收方时,上游代码还需要变更,显然不可行;这里可以采用多个consumer group订阅同一个topic消息方式,异步接收变更事件,在增加或减少接收方时,下游服务consumer group主动订阅或取消订阅商品信息变更topic即可,简要流程如下:
图片描述


leeon
301 声望12 粉丝

加油!