最近遇到的一个问题,记录一下。
上篇文章说到 SpringBoot Redis实现简单的发布/订阅
事情原委
我们目前项目中短信模块就是采用的 Redis 来作消息队列,起因是最近有应用反映下发短信时,偶尔会有发送两次的情况。
经过排查,确实是会存在,这个是我们研发之前的处理是发送短信后就会删除锁,这样如果出现网络波动的情况,就会出现发送两次的情况。
具体情况是这样,我们有两个实例,每个实例都订阅了topic,发送时会通知每个消费者,每个实例去获取锁,然后发送短信; 当时的情况是这样,生产者发送后,消费者开始消费 第一个实例消费的时间是 18:10:024,然后进行业务处理,发送短信完成时间是 18:10:056(通过日志查看到时间),处理得很快,几十毫秒就处理完了,然后把锁删除。 第二个实例消费的时间是 18:10:244,这时第一个实例已经处理完成,并且把锁删除掉,所以这时第二个实例尝试获取锁时会直接成功,接着进行业务处理,重新发送第二条短信完成时间是 18:10:268。 所以就造成偶尔会出现发送两次的情况。
找到问题所在就开始修复了,主要解决思路是让第二次获取锁失败就行了。
这里我们修改为获取锁进行业务处理完成之后,不直接删除锁,而是让它过一段时间失效,这样别的实例再此期间再获取锁时就不会成功了,即使第一次处理得很快,也不会被两次消费处理。
这里我们设置失效时间是 1分钟,后期可以根据业务情况进行调整。
总结
通过这次我们也知道,进行业务处理时,不光要进行加锁解锁,还要考虑各种情况;在处理消息队列时,重复消费是经常出现的问题,这里也算是收获一份经验了。
Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/redis重复消费问题