Topic 分区副本
在 Kafka 0.8.0 之前,Kafka 是没有副本的概念的,那时候人们只会用 Kafka 存储一些不重要的数据,因为没有副本,数据很可能会丢失。但是随着业务的发展,支持副本的功能越来越强烈,所以为了保证数据的可靠性,Kafka 从 0.8.0 版本开始引入了分区副本。也就是说每个分区可以人为的配置几个副本(比如创建主题的时候指定 replication-factor
,也可以在 Broker 级别进行配置 default.replication.factor
),一般会设置为3。
Kafka 可以保证单个分区里的事件是有序的,分区可以在线(可用),也可以离线(不可用)。在众多的分区副本里面有一个副本是 Leader,其余的副本是 follower,所有的读写操作都是经过 Leader 进行的,同时 follower 会定期地去 leader 上的复制数据。当 Leader 挂了的时候,其中一个 follower 会重新成为新的 Leader。通过分区副本,引入了数据冗余,同时也提供了 Kafka 的数据可靠性。
Kafka 的分区多副本架构是 Kafka 可靠性保证的核心,把消息写入多个副本可以使 Kafka 在发生崩溃时仍能保证消息的持久性。
Producer 往 Broker 发送消息
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 选举
在介绍 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;
数据一致性
这里说的一致性指的是不管是老的leader还是新的leader,consumer都能读到一样的数据

假设分区副本为3,副本0leader,副本1和2follower,在ISR列表里面副本0已经写入了message4,但是consumer只能读取message2,这是因为所有副本都同步了message2,只有High water mark以上的message才能被consumer读取,而High water mark取决于ISR列表里偏移量最小的分区,对应上图中的副本2;
所以在message还没有被follower同步完成时会被认为是"不安全的",如果consumer读取了副本0中的message4,这时候leader挂了,选举了副本1为新的leader,别的消费者去消费的时候就没有message4,就会造成不同的consumer消费的数据不一致,破坏了数据的一致性。
在引入了High water mark机制后,会导致broker之间的消息复制因为某些原因变慢,消息到达消费者的时间也会延长(需要等消息复制完了才能消费),延迟的时间可以通过参数来设置:replica.lag.time.max.ms(它指定了副本在复制消息时可被允许的最大延迟时间)
Log文件中的HW和LEO解释:
1:LEO(Log End Offset):每个副本的最后一个offset
2: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: 这只能保证副本之间的数据一致性, 并不能保证数据不丢失或不重复




