如何防止消息的重复消费_如何保证kafka消息不被重复消费?如何保证消息消费的幂等性?...

面试题

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

面试官心理分析

其实这是很常见的一个问题,这俩问题基本可以连起来问。既然是消费消息,那肯定要考虑会不会重复消费?能不能避免重复消费?或者重复消费了也别造成系统异常可以吗?这个是 MQ 领域的基本问题,其实本质上还是问你使用消息队列如何保证幂等性,这个是你架构里要考虑的一个问题。

面试题剖析

回答这个问题,首先你别听到重复消息这个事儿,就一无所知吧,你先大概说一说可能会有哪些重复消费的问题。

首先,比如 RabbitMQ、RocketMQ、Kafka,都有可能会出现消息重复消费的问题,正常。因为这问题通常不是 MQ 自己保证的,是由我们开发来保证的。挑一个 Kafka 来举个例子,说说怎么重复消费吧。

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 会再次传过来,如果此时消费者没有去重的话,那么就会导致重复消费。

187ac0113c2c88356b3e4109d7b10e33.png

如果消费者干的事儿是拿一条数据就往数据库里写一条,会导致说,你可能就把数据 1/2 在数据库里插入了 2 次,那么数据就错啦。

其实重复消费不可怕,可怕的是你没考虑到重复消费之后,怎么保证幂等性。

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

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

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

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

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

  • 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。
  • 比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。
  • 比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。
  • 比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。
a90ed9fa7a7ee081e94d45b3849acf05.png

当然,如何保证 MQ 的消费是幂等性的,需要结合具体的业务来看。

技术交流或者软件定制开发请私信“技术大牛”

ac02999b520925f790f3d29a285b4682.png
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 为了防止 Kafka 消息重复消费,可以采取以下几种方法: 1. 使用消费者组:Kafka 允许多个消费者以同一个消费者组的形式订阅同一个主题。当消息被发送到主题时,同一个消费者组中的消费者只会有一个消费者能够接收到消息。这就保证了每个消息只会被消费一次。如果需要进行消息重试,则需要使用不同的消费者组。 2. 使用消息偏移量(offset):Kafka 中每个分区都有一个唯一的偏移量,用于表示分区中已经被消费消息的位置。消费者可以记录下自己消费到的最后一个偏移量,并在下次启动时从该偏移量处开始消费。这种方式可以避免重复消费,但是需要注意,如果消费者处理消息失败,可能会导致消息被跳过而未被处理。 3. 使用幂等性生产者:幂等性生产者可以确保每个消息只会被发送一次,即使出现了网络故障或者其他异常情况。这样可以避免重复发送消息,从而避免重复消费。 4. 使用去重表:消费者可以使用一个去重表来记录已经消费过的消息,每次消费消息时先查询去重表,如果消息已经存在,则可以跳过该消息。这种方式可以避免重复消费,但是需要注意,去重表需要占用一定的内存空间,并且需要考虑去重表的并发访问问题。 ### 回答2: kafka是一种高吞吐量的分布式消息系统,但在实际应用中,消息重复消费是一个常见的问题。为了解决这个问题,kafka提供了以下几种机制来防止消息重复消费: 1. 分区复制:kafka消息分发到多个分区,并且可以将每个分区的副本分布在不同的Broker上。当消费者进行消费时,只有一个消费者可以消费同一个分区的消息,其他消费者无法消费相同的消息。这样可以保证消息在同一个分区内不会被重复消费。 2. 消费者组:kafka允许多个消费者组同时消费同一个主题的消息。每当一个新的消费者组加入时,kafka会为该消费者组分配一个独立的消费者实例。不同消费者组之间独立消费,可以避免重复消费。 3. 消息偏移量:kafka使用消息偏移量(offset)来标识消息在分区中的位置。消费者通过管理偏移量来确定下一个要消费消息消费者消费完一个消息后,会将偏移量提交给kafkakafka会保存最新的偏移量。当消费者再次启动后,会从上一次提交的偏移量开始消费,从而避免重复消费。 4. 消费者日志:kafka提供了一个特殊的主题__consumer_offsets,用于保存消费者的偏移量信息。每个消费者组的偏移量会被写入这个主题,当消费者启动时,会从这个主题读取之前提交的偏移量,以便从之前的位置继续消费。 综上所述,kafka通过使用分区复制、消费者组、消息偏移量和消费者日志等机制,有效地防止消息重复消费。这些机制结合起来,保证消息的可靠性和一致性,使得kafka成为一个可靠的分布式消息系统。 ### 回答3: Kafka通过以下几种机制来防止消息重复消费: 1. 分区偏移量(Partition Offset):每个消费者消费消息时会维护一个分区偏移量,用来标识已经消费消息的位置。消费者可以定期提交其消费的偏移量到Kafka集群,以便记录消费的进度。当消费者重新启动后,可以从上一次提交的偏移量位置继续消费,避免对同一条消息进行重复消费。 2. 消费者组(Consumer Group):在Kafka中,多个消费者可以组成一个消费者组,每个分区只能被同一个消费者组中的一个消费者消费。这样可以保证一个消息只会被同一个消费者组中的一个消费者消费一次,避免了重复消费的问题。 3. 提交消费偏移量(Commit Offset):消费者消费消息后,可以手动或自动将消费的偏移量提交给Kafka集群。当消费者发生故障或重新启动时,可以通过已提交的偏移量来恢复消费进度,继续消费消费消息。 4. 消息幂等性(Message Idempotence):生产者可以设置消息幂等性,确保同一消息可以被多次发送但只被消费一次。Kafka通过消息的唯一标识来判断是否是重复消息,如果一个生产者发送了多条相同消息,只有第一条消息会被写入Kafka并被消费,后续相同的消息会被认为是重复消息而被忽略。 通过以上机制,Kafka可以有效地防止消息重复消费消费者可以通过维护分区偏移量和消费者组的方式来保证消息只被消费一次,同时可以通过提交消费偏移量和使用幂等性消息防止重复消费的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值