十家面试,有八家会问的问题:“kafka会不会丢消息呢”。

kafka可以用于消息推送么 kafka消息会丢失吗_kafka

有些情况下消息可能会消失。这可能是由于配置错误或误解Kafka的内部原理所致。本文将解释数据丢失可能发生的情况

Provider(Publisher):确认的时候

当消息被发送到发布者时,发布者等待来自代理的确认(ACK)。有三个可用的配置选项:

  • acks = all - 当所有副本都确认已保存消息时,代理才会返回ACK。
  • acks = 1 - 当领导副本保存消息时返回ACK,但不会等待副本执行相同的操作。
  • acks = 0 - 生产者不会等待来自领导副本的确认。

由于最后一个选项显而易见的是:发送并忘记,第二个选项可能会导致数据丢失。在某种情况下,生产者将收到消息已保存的确认,但leader副本在确认之后宕机了并且无法启动。当新的副本被选举时没有该消息,所以消息永远消失了。

在JVM中,默认情况下ack设置为1,而在golang中为all。正如您所看到的,不同语言实现存在差异,因此最好显式设置此值。

Provider(Publisher):缓冲区

为了提高性能(或减少网络使用),机器会启用缓冲。当调用发布方法时,消息不会立即发送,而是在缓冲区达到最大容量或给定的时间间隔内发送。 这些行为由batch.size(以字节为单位)和linger.ms参数控制。如果达到其中任何一个限制,消息将立即发送。所以,这需要特别强调:客户端将收到消息已发送的信息,但这并不是真的。所以,如果应用程序在刷新缓冲区之前崩溃,则数据将无法恢复。所以消息永远消失了。

请注意,这些参数可能因语言实现不同而不同。在JVM中,batch.size是缓冲区中的字节数(默认为16384字节),但在kafka-go中,该参数描述了缓冲区中的消息数(默认为100)。更重要的是,JVM用户默认将linger.ms设置为0,但kafka-go用户将其设置为1秒。

在JVM实现中,尽管设置linger.ms = 0,消息仍然可以一起发送。这发生在负载较重的情况下 - 时间相近的消息将被批处理。

kafka可以用于消息推送么 kafka消息会丢失吗_kafka可以用于消息推送么_02

Consumer(Subscriber):Offsets

在消费消息时,消费者(订阅者)将其当前偏移量发送到代理。这是数据丢失可能发生的地方。

想象一种情况,一个消费者接收了两条消息:A 和 B。所有消息都在并行处理。处理消息时,B 成功了,偏移量被提交。然而,在处理消息 A 时,出现了一个错误。因为消息 B 的偏移量更大,Kafka 将保存最新的偏移量,消息 A 将永远不会返回给消费者。所以消息永远消失了。

Broker:已提交并不意味着已保存到磁盘

Kafka 在 Linux 系统上将消息保存到文件系统缓存(filesystem cache)中,但不会等待消息持久化到硬盘上。 这意味着如果只有一个副本或 acks=1即使Broker返回了 ACK,Broker也可能崩溃并丢失消息。所以消息永远消失了。

Broker:已保存到硬盘并不意味着它不会消失

leader 与 follower 在数据同步上是有时间差的。 例如,当一个 follower 代理落后于 leader,但仍被认为是同步的(滞后时间由 replica.lag.time.max.ms 参数配置,默认为 500),然后 leader 崩溃。新的 leader 被选举出来,但它没有收到消息。所以消息永远消失了。

总结

Kafka 是一个具有高容量、一致性和延迟的优秀工具。另一方面,很多这些东西取决于生产者、消费者以及broker的配置。

本文列举了几点消息可能丢失的场景。所以,面试遇到这个问题,抛出去就好了

本文是我翻译的一篇英文:When you can lose messages in Kafka

初始我用了 ChatGPT翻译了一遍,算是感受了下 ChatGPT 的魅力。准确率80%吧。但别误会,我又人工检验和修改了一遍。

然后我又问了 ChatGPT 一个问题,它也给了我答案。如下图

kafka可以用于消息推送么 kafka消息会丢失吗_kafka可以用于消息推送么_03