前言

消息传递语义:

  • at most once:最多一次。消息可能丢失也可能被处理,但最多只会被处理一次。
  • at least once:至少一次。消息不会丢失,但可能被处理多次。可能重复,不会丢失。
  • exactly once:精确传递一次。消息被处理且只会被处理一次。不丢失不重复就一次。

kafka有三次消息传递的过程:

  • 生产者发消息给 kafka broker
  • kafka broker 消息同步和持久化
  • kafka broker 将消息传递给消费者

在这三步中每一步都有可能会丢失消息。

一、生产者丢失消息

生产者发送消息的一般流程:

  • 1、生产者是与leader直接交互,所以先从集群获取topic对应分区的leader元数据;
  • 2、获取到leader分区元数据之后直接将消息发送过去;
  • kafka broker 对应的leader分区收到消息之后将消息写入文件持久化;
  • follower拉取leader消息与leader的数据保持一致;
  • follower消息拉取完毕之后给leader回复ACK确认消息;
  • kafka leader 和 follower分区同步完,leader分区给生产者回复ACK确认消息。

kafka消息会被重复消费码 kafka会不会丢消息_kafka

生产者采用push模式将数据发布到broker,每条消息追加到分区中,顺序写入磁盘。消息写入leader后,follower是主动与leader进行同步。

Kafka通过配置request.required.acks属性来确认消息的生产:

  • 0表示不进行消息接收是否成功的确认;不能保证消息是否发送成功,生成环境基本不会用。
  • 1表示当Leader接收成功时确认;只要Leader存活就可以保证不丢失,保证了吞吐量。
  • -1或者all表示Leader和Follower都接收成功时确认;可以最大限度保证消息不丢失,但是吞吐量低。

kafka producer 的参数acks 的默认值为1,所以默认的producer级别是at least once,并不能exactly once。

  • 如果acks配置为0,发生网络抖动消息丢了,生产者不校验ACK自然就不知道丢了。
  • 如果acks配置为1保证leader不丢,但是如果leader挂了,恰好选了一个没有ACK的follower,那也丢了。
  • all:保证leader和follower不丢,但是如果网络拥塞,没有收到ACK,会有重复发的问题。

二、kafka broker 丢失消息

Kafka Broker 接收到数据后会将数据进行持久化存储

kafka消息会被重复消费码 kafka会不会丢消息_kafka_02

操作系统本身有一层缓存,叫做 Page Cache,当往磁盘文件写入的时候,系统会先将数据流写入缓存中,至于什么时候将缓存的数据写入文件中是由操作系统自行决定。

Kafka提供了一个参数 producer.type 来控制是不是主动flush,如果Kafka写入到mmap之后就立即 flush 然后再返回 Producer 叫同步 (sync);写入mmap之后立即返回 Producer 不调用 flush 叫异步 (async)。

Kafka通过多分区多副本机制中已经能最大限度保证数据不会丢失,如果数据已经写入系统 cache 中但是还没来得及刷入磁盘,此时突然机器宕机或者掉电那就丢了,当然这种情况很极端。

三、消费者丢失消息

消费者通过pull模式主动的去 kafka 集群拉取消息,与producer相同的是,消费者在拉取消息的时候也是找leader分区去拉取。

多个消费者可以组成一个消费者组(consumer group),每个消费者组都有一个组id。同一个消费组者的消费者可以消费同一topic下不同分区的数据,但是不会出现多个消费者消费同一分区的数据。

消费者消费的进度通过offset保存在kafka集群的__consumer_offsets这个topic中。

消费消息的时候主要分为两个阶段:

  • 1、标识消息已被消费,commit offset坐标;
  • 2、处理消息。

场景一:先commit再处理消息。如果在处理消息的时候异常了,但是offset 已经提交了,这条消息对于该消费者来说就是丢失了,再也不会消费到了。

场景二:先处理消息再commit。如果在commit之前发生异常,下次还会消费到该消息,重复消费的问题可以通过业务保证消息幂等性来解决。

总结

kafka到底会不会丢消息?答案是:会!

Kafka可能会在三个阶段丢失消息:

(1)生产者发送数据;

(2)Kafka Broker 存储数据;

(3)消费者消费数据;

在生产环境中严格做到exactly once其实是难的,同时也会牺牲效率和吞吐量,最佳实践是业务侧做好补偿机制,万一出现消息丢失可以兜底。