Kafka 如何保证数据的可靠性
1. 数据的可靠性保证
为保证 producer 发送的数据,能可靠的发送到指定的 topic,topic 的每个 partition 收到producer 发送的数据后,都需要向 producer 发送 ack(acknowledgement 确认收到),如果 producer 收到 ack,就会进行下一轮的发送,否则重新发送数据。
2. 副本数据同步策略
方案 | 优点 | 缺点 |
---|---|---|
半数以上完成同步,就发送 ack | 延迟低 | 选举新的 leader 时,容忍 n 台节点的故障,需要 2n+1 个副 本 |
全部完成同步,才发送 ack | 选举新的 leader 时,容忍 n 台节点的故障,需要 n+1 个副 本 | 延迟高 |
Kafka 选择了第二种方案,原因如下:
- 同样为了容忍 n 台节点的故障,第一种方案需要 2n+1 个副本,而第二种方案只需要 n+1 个副本,而Kafka 的每个分区都有大量的数据,第一种方案会造成大量数据的冗余。
- 虽然第二种方案的网络延迟会比较高,但网络延迟对 Kafka 的影响较小。
3. AR、ISR、OSR
采用第二种方案之后,设想以下情景:leader 收到数据,所有 follower 都开始同步数据, 但有一个 follower,因为某种故障,迟迟不能与 leader 进行同步,那 leader 就要一直等下去, 直到它完成同步,才能发送 ack。这个问题怎么解决呢?
Kafka中,把 follower 可以按照不同状态分为三类 —— AR、ISR、OSR。
- 分区的所有副本称为 「AR」(Assigned Replicas —— 已分配的副本)
- 所有与leader副本保持一定程度同步的副本(包括 leader 副本在内)组成 「ISR」(In-Sync Replicas——在同步中的副本)
- 由于 follower 副本同步滞后过多的副本(不包括 leader 副本)组成 「OSR」(Out-of-Sync Replias)
- AR = ISR + OSR
- 正常情况下,所有的 follower 副本都应该与 leader 副本保持同步,即 AR = ISR,OSR 集合为空。
Leader 维护了一个动态的 in-sync replica set (ISR)
,意为和 leader 保持同步的 follower 集合。当 ISR 中的 follower 完成数据的同步之后,leader 就会给 follower 发送 ack。如果 follower 长时间 未 向 leader 同 步 数 据 , 则 该 follower 将 被 踢 出 ISR , 该 时 间 阈 值 由replica.lag.time.max.ms
参数设定。Leader 发生故障之后,就会从 ISR 中选举新的 leader。
4. ACK应答机制
对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失, 所以没必要等 ISR 中的 follower 全部接收成功。
所以 Kafka 为用户提供了三种可靠性级别,用户根据对可靠性和延迟的要求进行权衡, 选择以下的配置:
-
0:producer 不等待 broker 的 ack,这一操作提供了一个最低的延迟,broker 一接收到还没有写入磁盘就已经返回,当 broker 故障时有可能
丢失数据
;
-
1:producer 等待broker 的 ack,partition 的 leader 落盘成功后返回 ack
如果在 follower 同步成功之前leader 故障,那么将会
丢失数据
;
-
-1(all):producer 等待 broker 的 ack,partition 的 leader 和 follower 全部落盘成功后才返回 ack
但是如果在 follower 同步完成后,broker 发送 ack 之前,leader 发生故障,那么会造成
数据重复
。
5. 分区的leader和follower
在 Kafka 中,每个 topic 都可以配置多个分区以及多个副本。每个分区都有一个 leader 以及 0 个或者多个follower,在创建 topic 时,Kafka 会将每个分区的 leader 均匀地分配在每个 broker 上。我们正常使用 kafka 是感觉不到 leader、follower 的存在的。但其实,所有的读写操作都是由 leader 处理,而所有的 follower 都复制 leader 的日志数据文件,如果 leader 出现故障时,follower 就会被选举为 leader。所以,可以这样说:
- Kafka 中的 leader 负责处理读写操作,而 follower 只负责副本数据的同步
- 如果 leader 出现故障,其他 follower 会被重新选举为 leader
- follower 像一个 consumer 一样,拉取 leader 对应分区的数据,并保存到日志数据文件中
6. 故障处理
LEO:指的是每个副本最大的 offset;
HW:指的是消费者能见到的最大的 offset,ISR 队列中最小的 LEO
- follower 故障
- follower 发生故障后会被临时踢出 ISR,待该 follower 恢复后,follower 会读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 leader 进行同步。等该 follower 的 LEO 大于等于该 Partition 的 HW,即 follower 追上 leader 之后,就可以重新加入 ISR 了。
- leader 故障
- leader 发生故障之后,会从 ISR 中选出一个新的 leader,之后,为保证多个副本之间的数据一致性,其余的 follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 leader同步数据。
注:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。
- leader 发生故障之后,会从 ISR 中选出一个新的 leader,之后,为保证多个副本之间的数据一致性,其余的 follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 leader同步数据。
7. Controller介绍
- Kafka 启动时,会在所有的 broker 中选择一个 controller
- 前面 leader 和 follower 是针对 partition,而 controller 是针对 broker 的
- 创建 topic、或者添加分区、修改副本数量之类的管理任务都是由 controller 完成的
- Kafka 分区 leader 的选举,也是由 controller 决定的
8. Controller的选举
- 在 Kafka 集群启动的时候,每个 broker 都会尝试去 ZooKeeper 上注册成为 Controller(ZK临时节点)
- 但只有一个竞争成功,其他的 broker 会注册该节点的监视器
- 一但该临时节点状态发生变化,就可以进行相应的处理
- Controller 也是高可用的,一旦某个 broker 崩溃,其他的 broker 会重新注册为 Controller
9. Controller选举partition leader
- 所有 Partition 的 leader 选举都由 controller 决定
- controller 会将 leader 的改变直接通过 RPC 的方式通知需为此作出响应的 Broker
- controller 读取到当前分区的 ISR,只要有一个 Replica 还幸存,就选择其中一个作为 leader,否则,则任意选择一个 Replica 作为 leader
- 如果该 partition 的所有 Replica 都已经宕机,则新的 leader 为 -1
为什么不能通过ZK的方式来选举partition的leader?
- Kafka 集群如果业务很多的情况下,会有很多的 partition
- 假设某个 broker 宕机,就会出现很多的 partiton 都需要重新选举 leader
- 如果使用 zookeeper 选举 leader,会给 zookeeper 带来巨大的压力。所以,kafka 中 leader 的选举不能使用 ZK 来实现