Kafka到底会不会丢数据?

那么 Kafka 到底会不会丢数据呢?如果丢数据,究竟该怎么解决呢?
只有掌握了这些, 我们才能处理好 Kafka 生产级的一些故障,从而更稳定地服务业务 。
认真读完这篇文章,我相信你会对Kafka 如何解决丢数据问题,有更加深刻的理解 。

Kafka到底会不会丢数据?

文章插图
一、总体概述
越来越多的互联网公司使用消息队列来支撑自己的核心业务 。由于是核心业务,一般都会要求消息传递过程中最大限度做到不丢失,如果中间环节出现数据丢失,就会引来用户的投诉,年底绩效就要背锅了 。
那么使用 Kafka 到底会不会丢数据呢?如果丢数据了该怎么解决呢?为了避免类似情况发生,除了要做好补偿措施,我们更应该在系统设计的时候充分考虑系统中的各种异常情况,从而设计出一个稳定可靠的消息系统 。
大家都知道 Kafka 的整个架构非常简洁,是分布式的架构,主要由 Producer、Broker、Consumer 三部分组成,后面剖析丢失场景会从这三部分入手来剖析 。
Kafka到底会不会丢数据?

文章插图
二、消息传递语义剖析
在深度剖析消息丢失场景之前,我们先来聊聊「消息传递语义」到底是个什么玩意?
所谓的消息传递语义是 Kafka 提供的 Producer 和 Consumer 之间的消息传递过程中消息传递的保证性 。主要分为三种, 如下图所示:
Kafka到底会不会丢数据?

文章插图
  • 首先当 Producer 向 Broker 发送数据后,会进行 commit,如果 commit 成功,由于 Replica 副本机制的存在,则意味着消息不会丢失,但是 Producer 发送数据给 Broker 后,遇到网络问题而造成通信中断,那么 Producer 就无法准确判断该消息是否已经被提交(commit),这就可能造成 at least once 语义 。
  • 在 Kafka 0.11.0.0 之前, 如果 Producer 没有收到消息 commit 的响应结果,它只能重新发送消息,确保消息已经被正确的传输到 Broker,重新发送的时候会将消息再次写入日志中;而在 0.11.0.0 版本之后, Producer 支持幂等传递选项,保证重新发送不会导致消息在日志出现重复 。为了实现这个, Broker 为 Producer 分配了一个ID,并通过每条消息的序列号进行去重 。也支持了类似事务语义来保证将消息发送到多个 Topic 分区中,保证所有消息要么都写入成功,要么都失败,这个主要用在 Topic 之间的 exactly once 语义 。
其中启用幂等传递的方法配置:enable.idempotence = true 。
启用事务支持的方法配置:设置属性 transcational.id = "指定值" 。
  • 从 Consumer 角度来剖析, 我们知道 Offset 是由 Consumer 自己来维护的, 如果 Consumer 收到消息后更新 Offset, 这时 Consumer 异常 crash 掉, 那么新的 Consumer 接管后再次重启消费,就会造成 at most once 语义(消息会丢,但不重复) 。
  • 如果 Consumer 消费消息完成后, 再更新 Offset, 如果这时 Consumer crash 掉,那么新的 Consumer 接管后重新用这个 Offset 拉取消息, 这时就会造成 at least once 语义(消息不丢,但被多次重复处理) 。
总结:默认 Kafka 提供 「at least once」语义的消息传递,允许用户通过在处理消息之前保存 Offset 的方式提供 「at most once」 语义 。如果我们可以自己实现消费幂等,理想情况下这个系统的消息传递就是严格的「exactly once」, 也就是保证不丢失、且只会被精确的处理一次,但是这样是很难做到的 。
从 Kafka 整体架构图我们可以得出有三次消息传递的过程:
  • Producer 端发送消息给 Kafka Broker 端 。
  • Kafka Broker 将消息进行同步并持久化数据 。
  • Consumer 端从 Kafka Broker 将消息拉取并进行消费 。
【Kafka到底会不会丢数据?】在以上这三步中每一步都可能会出现丢失数据的情况, 那么 Kafka 到底在什么情况下才能保证消息不丢失呢?
通过上面三步,我们可以得出:Kafka 只对 「已提交」的消息做「最大限度的持久化保证不丢失」 。
怎么理解上面这句话呢?
  • 首先是 「已提交」的消息,当 Kafka 中 N 个 Broker 成功收到一条消息并写入到日志文件后,它们会告诉 Producer 端这条消息已成功提交了,那么这时该消息在 Kafka 中就变成 "已提交消息" 了 。
这里的 N 个 Broker 我们怎么理解呢?这主要取决于对 "已提交" 的定义, 这里可以选择只要一个 Broker 成功保存该消息就算已提交,也可以是所有 Broker 都成功保存该消息才算是已提交 。


推荐阅读