写在前面:作供应链业务一年有余了,这一年里MQ帮咱们解决了不少问题,在此作一些经验总结;另外,各个公司消息中间件提供的功能大同小异,最基础的推消息、下游异常重试机制应该是都具有的,本文所述也是创建在这样的能力基础上的~
场景一:削峰填谷,下降响应时间,下游异常自动重试、保证成功redis
举例:对库存模块而言,入库是一个增量操做,当经过了数据校验以后就理应执行成功,但入库操做经常伴有复杂的写库逻辑及乐观锁冲突,同步模型平均响应时间长,且并发条件下乐观锁冲突失败几率较大;这里就能够引入MQ,将写库操做异步处理,简要流程以下:segmentfault
须要注意的是:
一、若是有重复发消息地可能性,MQ下游须要作业务幂等,整条链路要有并发锁保护(redis实现并发悲观锁可参看文章:https://segmentfault.com/a/11...);
二、若是下游触发异常,中间件通常会自动重试(并发乐观锁冲突自动重试可解决,中间件通常会提供一直重试、从新入队、丢弃消息等模式,需根据具体场景选取,在此再也不赘述);若是是非重试可以解决的异常,则须要再监控到异常后,人工介入跳过、修复、补偿;
三、示例状况是上游无写库,若是上游有写库,可能出现发消息与事务写库两个事件状态不一致的状况,通常会有三种状况:并发
(1)先事务写库,再发消息;当发消息失败时,写库事务已提交,没法回滚; (2)先发消息,再事务写库;当写库失败时,消息已发送,没法回滚; (3)写库事务中发消息,若是发消息失败,事务能够回滚,但若是发消息成功后,事务提交时失败(有这种可能),消息也没法回滚;
若是上游没法避免写库时,咱们通常采用先事务写库,再发送消息,由于消息中间件做为基础服务,通常是可靠的,很小几率出现发消息失败;若是出现了,有两种处理方式:异步
(1)发消息失败,返回客户端失败,则须要脚本补偿,回滚上游写库; (2)发消息失败,只报警,但返回客户端正常,则须要补偿消息;
场景二:异步处理,服务解耦
举例:每一次操做库存后都须要记录业务操做日志,每一个Stock(库存服务)接口都须要在完成库存逻辑后,再调用Log(日志服务)记录操做日志;若是采用同步调用模型,Stock服务就与Log服务耦合,依赖于Log服务的实时响应结果,若是Log服务挂了,Stock服务也就挂了,这不是咱们指望看到的;这里就能够引入MQ实现核心流程与非核心流程的解耦,简要流程以下:spa
这样,上游只需依赖MQ,通常而言,相比下游服务,中间件是更可靠的;经过MQ的能力,若是下游出现问题,主流程不会阻塞,有更多的时间修复,且更易补偿;日志
场景三:多下游的发布订阅
举例:商品信息做为供应链基础数据,在几乎全部系统都有应用;若是商品信息变动,其余系统就须要接收变动信息,如何通知就是一个问题;同步通知模型会耦合全部下游服务,响应时间长,在增长或减小接收方时,上游代码还须要变动,显然不可行;这里能够采用多个consumer group订阅同一个topic消息方式,异步接收变动事件,在增长或减小接收方时,下游服务consumer group主动订阅或取消订阅商品信息变动topic便可,简要流程以下:code