如何保证消息不被重复消费

如何保证消息不被重复消费?(如何保证消息消费的幂等性)

举个例子吧。假设你有个系统,消费一条消息就往数据库里插入一条数据,要是你一个消息重复两次,你不就插入了两条,这数据不就错了?可是你要是消费到第二次的时候,本身判断一下是否已经消费过了,如果就直接扔了,这样不就保留了一条数据,从而保证了数据的正确性。数据库

一条数据重复出现两次,数据库里就只有一条数据,这就保证了系统的幂等性。微信

幂等性,通俗点说,就一个数据,或者一个请求,给你重复来屡次,你得确保对应的数据是不会改变的,不能出错。blog

因此第二个问题来了,怎么保证消息队列消费的幂等性?队列

其实仍是得结合业务来思考,我这里给几个思路:进程

  • 好比你拿个数据要写库,你先根据主键查一下,若是这数据都有了,你就别插入了,update 一下好吧。开发

  • 好比你是写 Redis,那没问题了,反正每次都是 set,自然幂等性。kafka

  • 好比你不是上面两个场景,那作的稍微复杂一点,你须要让生产者发送每条数据的时候,里面加一个全局惟一的 id,相似订单 id 之类的东西,而后你这里消费到了以后,先根据这个 id 去好比 Redis 里查一下,以前消费过吗?若是没有消费过,你就处理,而后这个 id 写 Redis。若是消费过了,那你就别处理了,保证别重复处理相同的消息便可。消息队列

  • 好比基于数据库的惟一键来保证重复数据不会重复插入多条。由于有惟一键约束了,重复数据插入只会报错,不会致使数据库中出现脏数据。it

剖析

首先,好比 RabbitMQ、RocketMQ、Kafka,都有可能会出现消息重复消费的问题,正常。由于这问题一般不是 MQ 本身保证的,是由咱们开发来保证的。挑一个 Kafka 来举个例子,说说怎么重复消费吧。zookeeper

Kafka 实际上有个 offset 的概念,就是每一个消息写进去,都有一个 offset表明消息的序号,而后 consumer 消费了数据以后,每隔一段时间(定时按期),会把本身消费过的消息的 offset 提交一下,表示“我已经消费过了,下次我要是重启啥的,你就让我继续从上次消费到的 offset 来继续消费吧”。

可是凡事总有意外,好比咱们以前生产常常遇到的,就是你有时候重启系统,看你怎么重启了,若是碰到点着急的,直接 kill 进程了,再重启。这会致使 consumer 有些消息处理了,可是没来得及提交 offset,尴尬了。重启以后,少数消息会再次消费一次。

举个栗子。

有这么个场景。数据 1/2/3 依次进入 kafka,kafka 会给这三条数据每条分配一个 offset,表明这条数据的序号,咱们就假设分配的 offset 依次是 152/153/154。消费者从 kafka 去消费的时候,也是按照这个顺序去消费。假如当消费者消费了 offset=153 的这条数据,刚准备去提交 offset 到 zookeeper,此时消费者进程被重启了。那么此时消费过的数据 1/2 的 offset 并无提交,kafka 也就不知道你已经消费了 offset=153 这条数据。那么重启以后,消费者会找 kafka 说,嘿,哥儿们,你给我接着把上次我消费到的那个地方后面的数据继续给我传递过来。因为以前的 offset 没有提交成功,那么数据 1/2 会再次传过来,若是此时消费者没有去重的话,那么就会致使重复消费。

若是消费者干的事儿是拿一条数据就往数据库里写一条,会致使说,你可能就把数据 1/2 在数据库里插入了 2 次,那么数据就错啦。 如感受文章对你有所帮助,能够关注微信公众号【五彩的颜色】鼓励一下

相关文章
相关标签/搜索