- 消息中间件MQ场景问题及解决办法
- 问题背景
- 一、消息丢失问题
- 二、消息重复消费问题
- 三、垃圾消息问题
- 四、延时消费问题
- 总结
问题背景
业务场景:秒杀 ——> 下单 ——> 支付
这三个核心流程中,真正并发量大的是秒杀功能,下单和支付功能实际并发量很小。
所以,我们在设计秒杀系统时,有必要把下单和支付功能从秒杀的主流程中拆分出来,
特别是下单功能要做成mq异步处理的。而支付功能,比如支付宝支付,是业务场景本身保证的异步。
一、消息丢失问题
问题背景:上一步秒杀 *** 作成功了,发送消息的时候出现网络问题或broker挂了等原因,导致消息发送失败,造成消息丢失
解决办法:增加一张消息发送表
具体实现:在生产者发送消息到mq之前,先把这条消息写入消息发送表,消息初始状态是待处理,后在发送mq消息,消费者消费消息时,处理完业务逻辑之后,再回调生产者这个接口,修改消息状态为已处理。
遗留问题:如果生产者已经把消息写入消息发送表了,再发送消息到mq服务端的过程失败了,造成了 消息的丢失,如何处理?
解决办法:使用job,增加重试机制
具体实现:用job,每隔一段时间去查询消息发送表中状态为待处理的数据,然后重新发送mq消息。
遗留问题:那这样是不是也有可能消息被重复消费?
二、消息重复消费问题
问题背景:如果我们设置了ack机制,当出现网络问题时,ack应答超时,本身就有可能造成消息重复消费,而且我们还设置了job,定时重新发送消息,这样使消息的重复消费的几率大大增加。
解决办法:增加一张消息处理表
具体实现:消费者读到消息之后,先判断一下消息处理表,是否存在该消息,如果存在,表示重复消费,则直接返回。 如果不存在,则进行正常 *** 作,接着将消息写入消息处理表中,再返回。
注意点: 进行正常业务逻辑 *** 作和将消息写入消息处理表中,这个两个 *** 作要放在一个事务当中,保证原子性。
三、垃圾消息问题
问题背景:上面逻辑看着没啥大问题,但是如果出现消息消费失败的情况。比如:由于某些原因,消 息消费者下单一直失败,一直不能回调状态变更接口,job一直重试,最后导致大量垃圾消息
解决办法:设置发送消息次数
具体实现:每次在job重试的时候,需要判断一下消息发送表中该消息的发送次数是否到达最大限制,如果达到了最大限制,直接返回。如果没有达到,则将次数+1,然后发送消息。这样如果出现异常,也只会产生少量的垃圾消息,不会影响到正常的业务。
四、延时消费问题
问题背景:用户秒杀成功,下单之后,30分钟之内未进行支付,该订单会被自动取消,回退库存。
实现方法可以用job,但job有个问题,需要每隔一段时间处理一次,实时性不是很好我们还可以用延时队列,rocketMq自带了延时队列的功能
具体实现:下单时消息生产者会生成一张订单,此时的状态为待支付,然后向延时队列中发送一条消息,当到达延时时间,消息消费者读取消息之后,会查询该订单的状态是否为待支付。如 果是待支付状态,则更新订单状态为取消状态。如果不是待支付,说明该订单已经支付过了,则直接返回;
注意点: 用户完成支付之后,会修改订单状态为已支付。
总结
这个场景也是会经常遇到的,看到别人的总结,感觉思路不错,整理一下,以后遇到其他的场景也可以有自己思路。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)