Kafka如何保证数据的可靠性和一致性
Kafka 可以保证单个分区里的事件是有序的,分区可以在线(可用),也可以离线(不可用)。在众多的分区副本里面有一个副本是 Leader,其余的副本是 follower,所有的读写操作都是经过 Leader 进行的,同时 follower 会定期地去 leader 上的复制数据。当 Leader 挂了的时候,其中一个 follower 会重新成为新的 Leader。通过分区副本,引入了数据冗余,同时也提供了 Kafka 的数据可靠性。
Kafka 的分区多副本架构是 Kafka 可靠性保证的核心,把消息写入多个副本可以使 Kafka 在发生崩溃时仍能保证消息的持久性。
Kafka 在 Producer 里面提供了消息确认机制。也就是说我们可以通过配置来决定消息发送到对应分区的几个副本才算消息发送成功。
对于某些不太重要的数据,对某些数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等待ISR中的follower全部接受成功;
kafka为用户设置了三种可靠性级别,通过acks参数设定:
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发生故障,那么会造成数据重复;
同时极端情况下,ISR的follower为0, broker故障时也会丢失数据
另外,Producer 发送消息还可以选择同步(默认,通过 producer.type=sync 配置) 或者异步(producer.type=async)模式。如果设置成异步,虽然会极大的提高消息发送的性能,但是这样会增加丢失数据的风险。如果需要确保消息的可靠性,必须将 producer.type 设置为 sync。
在介绍 Leader 选举之前,让我们先来了解一下 ISR(in-sync replicas)列表。每个分区的 leader 会维护一个 ISR 列表,ISR 列表里面就是 follower 副本的 Borker 编号,只有跟得上 Leader 的 follower 副本才能加入到 ISR 里面,这个是通过 replica.lag.time.max.ms 参数配置的,具体可以参见 《一文了解 Kafka 的副本复制机制》。只有 ISR 里的成员才有被选为 leader 的可能。
所以当 Leader 挂掉了,而且 unclean.leader.election.enable=false 的情况下,Kafka 会从 ISR 列表中选择第一个 follower 作为新的 Leader,因为这个分区拥有最新的已经 committed 的消息。通过这个可以保证已经 committed 的消息的数据可靠性。
综上所述,为了保证数据的可靠性,我们最少需要配置一下几个参数:
- producer 级别:acks=all(或者 request.required.acks=-1),同时发生模式为同步 producer.type=sync
- topic 级别:设置 replication.factor>=3,并且 min.insync.replicas>=2;
- broker 级别:关闭不完全的 Leader 选举,即 unclean.leader.election.enable=false;
Log文件中的HW和LEO
LEO(Log End Offset):每个副本的最后一个offset
HW(Hight watermark):所有副本中最小的LEO
-------------------------------------------
LEO: 指的是每个副本中最大的offset
HW: 对于消费者来说,一致性是能见到的最大的offset, ISR队列中最小的LEO, 因为要保证消费者消费消息的一致性【保证消费一致性】
(1)follower故障
follower发生故障后会被临时剔除ISR, 待该follower 恢复后,follower会读取本地磁盘记录的上次HW, 并将log文件高于HW的部分截取掉,从HW开始向leader进行同步, 等待该follower的LEO大于该partition的HW,即follower追上LSR之后,就可以重新加入ISR了。
(2)leader故障
leader发生故障之后,会从ISR中选举一个新的leader,为保证多个副本间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据【保证存储一致性】
PS: 这只能保证副本之间的数据一致性, 并不能保证数据不丢失或不重复