共计 848 个字符,预计需要花费 3 分钟才能阅读完成。
使用了消息队列,如何保证消息不重复消费?
这个问题等价于如何保证消息消费时的幂等性?
我们先来看看是如何产生重复消费的。消息中间件有rabbitmq、rocketmq、kafka等,都可能出现重复消费,拿kafka举例吧,公司的系统用的kafka最近出现过这个问题。
kafka有offset的概念,就是消息偏移量。消费时就是根据这个偏移量来判断是否消费过的。当消息对应的业务处理完了之后,就需要往kafka提交消息,就是把消息的offset提交,下次就从上次消费到的offset继续消费。但是,当提交offset的时候,失败了,比如,Heartbeat failed for group ****** because it is rebalancing,就是kafka在做重平衡的时候,就可能出现提交失败,那么下次,这条消息就会再次被消费。
重复消费其实没什么,可怕的是没考虑消费的幂等性,不然消费多次,等于业务被处理多次,很可能造成很多意想不到的问题。
如何保证消费的幂等性?
先总结主要做法:消费幂等性主要是靠具体业务来保证的!
另外,比如
- 基于数据库的唯一键来保证插入不会重复插入;
- 发送消息加全局唯一ID,消费过的ID可以存储在redis中,在消费时去redis 查一下是否存在,存在就说明处理过了,不存在再消费即可,redis的数据做超时限制。
- 注:有些人说将消息去重,去重的前提是需要消息有一个唯一ID,不然消息就算完全一致,也不定代表是重复的消息。
如何保证顺序消费?
顺序消费这样的场景实际生产中是很少的,全局的顺序是很难保证的,甚至说是不可能实现的。
要保证顺序,就要保证发送端限制异步发送,接收端限制并行消费。这个在实际业务层面是很难实现的,或者说没有实际意义。
比如RocketMQ有队列机制,先进先出FIFO,可以保证发送有序,但是消费端的有序还是要靠业务保证。kafka也只能做到保证局部有序,不能全局有序。kafka每个分区都是一个完全有序的日志,但是分区之间没有全局排序(除了你的消息中可能包含的一些挂钟时间)