[Kafka] Kafka如何保证消息不丢失、不重复

  • Kafka基本架构
  • Kafka如何保证消息不丢失、不重复
  • Kafka消息的丢失和重复可能会发生在哪里?
  • Kafka如何保证`生产者端`的消息不丢失、不重复?
  • 生产者端`丢失数据`的情况分析
  • 生产者端`丢失数据`的解决办法
  • 生产者端`重复发送数据`的情况分析及解决办法
  • 消费者端`丢失数据`的情况分析及解决办法
  • 消费者端`重复消费数据`的情况分析及解决办法


Kafka基本架构

kafka支持多少个生产者 kafka生产者key能重复吗_kafka

  • 生产者Producer :生产信息;
  • 消费者Consumer :订阅主题、消费信息;
  • 代理Broker : 可以看作是一个独立的 Kafka 实例。多个 Kafka Broker 组成一个卡夫卡集群 Kafka Cluster
  • 主题topic:可以理解为一个队列, 生产者和消费者面向的都是一个 topic, Producer 将消息发送到特定的主题,Consumer 通过订阅特定的主题来消费消息;
  • 分区partition: 为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。
  • 副本Replica: :副本,为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且 kafka 仍然能够继续工作,kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,一个 leader 和若干个 follower。
  • leader :每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 leader。
  • follower :每个分区多个副本中的“从”,实时从 leader 中同步数据,保持和 leader 数据的同步。leader 发生故障时,某个 follower 会成为新的 follower。

Kafka如何保证消息不丢失、不重复

Kafka消息的丢失和重复可能会发生在哪里?

根据以上的Kafka架构图,我们推测一下,消息丢失可能会发生在哪里?

  • 生产者丢失数据
  • 消费者丢失数据

那么消息重复消费可能会发生在哪里?

同样也是在消费者端和生产者端,即:

  • 生产者重复发送数据
  • 消费者重复消费数据

如何保证消息的有序?

  • 同步发送模式:发出消息后,必须等待阻塞队列收到通知后,才发送下一条消息;同步发送模式可以保证消息不丢失、又能保证消息的有序性。
  • 异步发送模式:生产者一直向缓冲区写消息,然后一起写到队列中;好处是吞吐量大,性能高。

Kafka如何保证生产者端的消息不丢失、不重复?

生产者端丢失数据的情况分析

  1. 生产者端使用同步发送模式,有三种状态保证消息被安全生产,即配置acks参数(默认为1):
    1:集群的leader节点收到消息后,就可以发回成功写入的通知
    0:生产者在成功写入消息之前不会等待来着服务器的任何响应,即不在乎消息是否丢失了
    3:集群中的所有节点都收到消息时,才发回成功写入的通知,这种方式最可靠,但是性能最低
    因此,当使用参数1且leader节点在写入参数时挂掉了,数据就会丢失。
  2. 使用异步模式时,当缓冲区满了,如果配置为0,则还没收到确认的情况下,缓冲区一满就会清空缓冲区中的消息,数据就丢失了

生产者端丢失数据的解决办法

  1. 同步模式下,将发送消息的确认机制设置为-1,使得所有节点确认后再发送下一条数据即可
  2. 异步模式下,如果消息发送出去了,但还没有收到确定的时候,在配置文件中设置成不限制阻塞超时的时间,即让生产者一直保持等待,也可以保证数据不丢失

生产者端重复发送数据的情况分析及解决办法

重复发送数据,不用管,在消费者端建立去重表即可。


消费者端丢失数据的情况分析及解决办法

如果消息在处理完成前就提交了offset,就有可能造成数据的丢失。解决办法是在后台提交位移前确保消息已经被正常处理了,然后手动提交offset(调用**commitSync()**函数)。

附注:offset(偏移量)是什么?
Kafka中每一个分区partition都由一系列有序的、不可变的消息组成,这些消息被连续地追加到partition中,partition中的每个消息都有一个连续的序号,用于唯一标识一条消息,offset就记录着下一条将要发送给消费者的消息的序号,offset从语义上来看有两种:

  1. Current Offset
  2. Committed Offset

Current Offset保存在消费者的客户端中,它表示希望收到的下一条消息的序号,Offset保证每次消费者消费信息时,都能收到正确位置的消息。

Committed Offset保存在broker上,它表示消费者已经确认消费过的消息的序号,这个确认需要消费者调用commitSync()函数,如果调用了这个函数,Commit Offset会被更新为Current Offset的值,如果没有调用这个函数,那么它就不会改变,依然是0。它保证新的消费者能够从正确的位置开始消费信息,从而避免重复消费。

消费者端重复消费数据的情况分析及解决办法

在消费者端建立去重表即可保证消息只会被消费一次。


附注:Kafka的消息是消费完就消失的吗?
kafka中的数据的删除和消费者是否消费无关,数据的删除只与kafka broker中 的数据保存时间(log.retention.hours=48,数据最大保存48小时)和数据最大保存内存(log.retention.bytes=1073741824,数据最大保存1G)有关。