需要从生产者和消费者两个角度分析重复消费的问题;
producer端
消息重复场景,发生在重试时
可恢复异常时重试和不可恢复异常时回调函数进行消息重发,均可能导致消息重复;
解决方案:
开启 kafka的幂等性功能配置(该配置默认为false)
prop.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG,true) ;
在消息生产时,mg内部针对每条生产者发送的消息生成一个唯一id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;
consumer端
重复消费场景
正常情况下,拉取消息之后先处理消息,然后进行位移提交。
如果在拉取消息进行消费,但是下一次提交位移之前消费者崩溃了,或者在消费者关闭之前调用了 consumer.unsubscribe()方法取消订阅,那么下一次就还得在
上一次消费位移的位置重新开始消费,造成重复消费
解决方案:
在消息消费时,要求消息体中也要有全局唯一id作为去重和幂等的依据,避免同一条消息被重复消费;
利用一张日志表来记录已经处理成功的消息的ID,如果新到的消息ID 已经在日志表中,那么就不再处理这条消息。
造成消息重复的根本原因是:网络不可达。
所以解决这个问题的办法就是绕过这个问题。那么问题就变成了:如果消费端收到两条一样的消息,应该怎样处理?
消费端处理消息的业务逻辑保持幂等性。只要保持幂等性,不管来多少条重复消息,最后处理的结果都一样。
保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现。
利用一张日志表来记录已经处理成功的消息的ID,如果新到的消息ID已经在日志表中,那么就不再处理这条消息。