持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,[点击查看活动详情]
消息队列在工作中经常使用,主要用来解耦业务、异步消费、承接瞬时流量,前段时间业务上刚好需要使用到队列,公司队列使用的是rabbitmq,今天我来讲下rabbitmq的ack确认机制。
业务场景:物流系统推送物流付款单,由于涉及到money所以业务数据很重要,于是想到rabbitmq有消息确认机制,只有消费成功才会将消息丢弃,否则会重入队列。
遇到的问题:
- 问题一: 在对接的过程中由于某些数据问题导致业务异常,导致一些消息一直重入队列,于是导致后面的消息无法被消费,这里发现nack后消息重入队列是在队列头部的,也就是第一个消息。
解决方案:消费异常之后将消息重新投递到队列,然后在手动ack消费成功,这样子就将消息丢到队尾了。
解决方案2:使用spring的retry重试机制,在消费失败后会在本地重试就不会再去返回队列重试,但是这里需要注意,如果本地重试出现异常将重试失败。
- 问题二: 在上面的问题解决后,又发现某些消息一直在队列里消费不成功,debug发现会存在数据问题,但是消息又不能丢弃。
解决方案1:设置三次重试机会,每次重试都会去redis缓存重试次数,将重试次数加一,达到三次后将消息存入MySQL,由本地消息表记录,再由定时任务重新消费,如果还是不能消费成功那就将消息记录状态改为异常,根据业务需要可以在前端页面展示。
补充:在上述问题中应该做好日志的记录,如果可以我们可以将业务异常和系统异常分开,比如数据问题和网络超时,对于重要的数据千万不能丢失,哪怕是保存在日志里也可以,万一那天你的上级需要这些数据问你,你却没有(提桶~)。
画了一个大致的流程图如下: