请点击【关注】获取更多互联网和技术干货,头条号IT徐胖子原创本文请勿转载,感谢支持
1 消息中间件应用场景
本文我们来分析自订阅消息时幂等性问题怎么解决。消息中间件主要有三个作用:系统间解耦,异步化,流量削峰。我们通过一个电商场景实例来说明。
1.1 系统间解耦
假设你在一个电商系统购物,支付成功后,系统应该怎么把这个消息告诉物流系统?有两种思路:
方式一:支付系统直接调用物流系统。这样会有一个问题:支付系统和物流系统产生了强依赖,当物流系统出现问题,直接影响用户交易流程,导致支付失败。
方式二:支付系统把支付成功消息推送给消息中间件,然后交易流程结束。物流系统订阅这个消息进行后续处理。这样即使物流系统出现问题,也不影响交易系统。
1.2 异步化
假设物流系统处理业务需要100毫秒。
采用方式一:整个链路响应时长就增加了100毫秒,耗时增加。
采用方式二:整个链路时长就不需要增加100毫秒,这就是异步化带来性能提升。
1.3 流量削峰
假设双11商家做秒杀活动,每秒产生了大量订单数据。
采用方式一:支付系统压力就会传递给物流系统,这是没有必要的。
采用方式二:物流系统可以根据系统能力,匀速拉取数据处理,削减流量洪峰。
现在有一个问题需要思考:消息订阅方接收到消息中间件发送来的消息后,给出了成功接收的响应,但是由于网络原因消息中间件没有收到,消息中间件是重新发送还是默认接收方已经收到了?
在互联网公司实践中消息中间件会再发一次消息,保证消息不丢,但是不保证不重复,所以我们必须要解决幂等问题。
2 幂等解决方案
操作一次和操作多次结果一致被称为幂等,我们来分析几种常用幂等解决方案。
2.1 幂等表方案
场景:用户支付成功(订单ID=aaa)此时支付系统将支付成功的消息,发送至消息队列。物流系统订阅到这个消息,准备为这笔订单创建物流单。
但是消息队列有可能会重复推送,也就是说物流系统有可能接收到多次这条消息。我们希望达到的效果是:无论接收到多少条重复消息,只能创建一笔物流单。
方案:新建一张幂等表,该表就是用来做幂等的,无其它业务意义。该表有一个字段名为key,建有唯一索引,这个字段是幂等的标准。
当物流系统订阅到消息后,在创建物流单前,首先要将订单ID(本例=aaa)尝试插入幂等表的key字段。如果插入成功则继续做业务。不成功表示已经处理过了,丢弃消息。
这张表所有业务都可以操作,数据量会很大,需要定期清理,并将数据备份。
当然可以利用分布式锁锁住订单ID,判断是否已经有物流订单了,没有就创建物流订单,本质上是在解决并发问题。
2.2 状态机方案
场景:物流单处理成功,发送消息给订单系统,让订单更新状态为完成,假设操作是将订单status=0更新至status=1。同理订单系统也可能收到多条消息。
方案:status=0只能流转至status=1,当订单为status=1时即使接收到物流单成功的消息也不再处理。
2.3 乐观锁方案
在设计数据表时为数据库记录增加version字段,在更新数据时先查出数据,数据中包含version字段,执行如下更新语句。如果此时该记录已经被修改,version就已经发生了变化不能被更新成功:
update xxx set xxx, version = #{version} + 1 where id = #{id} and version = #{version}
3 文章总结
消息中间件在互联网场景中有着广泛应用,重复消费消息问题是在订阅消息时必须要解决的问题,一定要做好幂等方案,否则会给业务造成很多问题。
请点击【关注】获取更多互联网和技术干货,头条号IT徐胖子原创本文请勿转载,感谢支持