Kafka是如何保障数据不丢失的?
该题属于高频出现的面试题,是从Kafka的Broker侧来看待数据丢失的问题。
1、Kafka的Broker机制保证了数据的不丢失。
对于Kafka的Broker而言,Kafka 的复制机制和分区的多副本机制是Kafka 可靠性保证的核心。把消息写到多个副本中能保证在Kafka服务器崩溃后能够继续保证消息持久性。
知道问题的核心,来看三个配置参数来回答该问题。
- Topic 副本因子个数:replication.factor >= 3
- 同步副本列表(ISR):min.insync.replicas = 2
- 禁用unclean选举:unclean.leader.election.enable=false
副本因子
Kafka的topic可以分区,并且可以为分区配置多个副本,可以通过replication.factor参数实现配置。Kafka的分区副本包含两种类型:Leader Replica和Follower Replica,每个分区在创建时都会选举一个副本作为Leader副本,其余都是Follower副本。而Follower副本对外不提供任何服务,即任何Follower副本不会响应消费者和生产者的读写请求,所有请求都得由Leader副本来处理。所以,所有读写请求都必须发往Leader副本所在的Broker,由该 Broker 负责处理。Follower副本不处理客户端请求,唯一任务是从Leader副本异步拉取消息,并写入到自己的提交日志中,从而实现与Leader副本的同步。
一般来说,副本设为3可以满足大部分的使用场景,也有可能是5个副本(比如银行)。如果副本因子为N,那么在N-1个broker 失效的情况下,仍然能够从topic读取数据或向topic写入数据。所以,更高的副本因子会带来更高的可用性、可靠性和更少的故障。另一方面,副本因子N需要至少N个broker ,而且会有N个数据副本,也就是说它们会占用N倍的磁盘空间。实际生产环境中一般会在可用性和存储硬件之间作出权衡。
副本的分布同样也会影响可用性。默认情况下,Kafka会确保分区的每个副本分布在不同的Broker上,但是如果这些Broker在同一个机器上,一旦机器的交换机发生故障,分区将不可用。所以建议把Broker分布在不同的机器上,可以使用broker.rack参数配置Broker所在机器的名称。
同步副本列表
In-sync replica(ISR)称为同步副本,ISR中的副本都是与Leader副本数据状态同步的副本。
ISR存在哪些副本呢?Leader副本总是存在于ISR中。以及与Leader副本保持了“同步”的follower副本。Kafka的broker端有一个参数replica.lag.time.max.ms, 该参数表示follower副本滞后于Leader副本的最长时间间隔,默认是10秒。意味着只要follower副本落后于leader副本的时间间隔不超过10秒,就可以认为该follower副本与leader副本是同步的。
可以看出ISR是一个动态的。所以即便是为分区配置了3个副本,还是会出现同步副本列表中只有一个副本的情况(其他副本由于不能够与leader及时保持同步,被移出ISR列表)。如果这个同步副本变为不可用,我们必须在可用性和一致性之间作出选择(CAP理论)。
根据Kafka对可靠性的定义,消息只有在写入所有同步副本之后才被认为是已提交的。但如果这里的“所有同步副本”只包含一个同步副本,那么在这个副本变为不可用时,数据就会丢失。(某副本宕机后,没有副本保存原有数据状态。)
如果要确保已提交的数据被写入不止一个副本,就需要把最小同步副本数量设置为大一点的值。对于一个包含3 个副本的主题分区,如果min.insync.replicas=2,那么至少要存在两个同步副本才能向分区写入数据。(满足这个条件,生产者才能将生产的数据放入消息队列中)
举例:如果进行了上面的配置,此时必须要保证ISR中至少存在两个副本,如果ISR中的副本个数小于2,那么Broker就会停止接受生产者的请求。尝试发送数据的生产者会收到NotEnoughReplicasException异常,消费者仍然可以继续读取已有的数据。
禁用unclean选举
选择一个同步副本列表中的分区作为leader 分区的过程称为clean leader election。注意,这里要与在非同步副本中选一个分区作为leader分区的过程区分开,在非同步副本中选一个分区作为leader的过程称之为unclean leader election。由于ISR是动态调整的,所以会存在ISR列表为空的情况,通常来说,非同步副本落后 Leader 太多,因此,如果选择这些副本作为新 Leader,就可能出现数据的丢失。毕竟,这些副本中保存的消息远远落后于老 Leader 中的消息。在 Kafka 中,选举这种副本的过程可以通过Broker 端参数 unclean.leader.election.enable控制是否允许 Unclean 领导者选举。开启 Unclean 领导者选举可能会造成数据丢失,但好处是,它使得分区 Leader 副本一直存在,不至于停止对外提供服务,因此提升了高可用性。反之,禁止 Unclean Leader 选举的好处在于维护了数据的一致性,避免了消息丢失,但牺牲了高可用性。分布式系统的CAP理论说的就是这种情况。
不幸的是,unclean leader election的选举过程仍可能会造成数据的不一致,因为同步副本并不是完全同步的。由于复制是异步完成的,因此无法保证follower可以获取最新消息。比如Leader分区的最后一条消息的offset是100,此时副本的offset可能不是100,这受到两个参数的影响:
replica.lag.time.max.ms:同步副本滞后leader副本的时间
zookeeper.session.timeout.ms:与zookeeper会话超时时间
简而言之,如果我们允许不同步的副本成为leader,那么就要承担丢失数据和出现数据不一致的风险。如果不允许它们成为leader,那么就要接受较低的可用性,因为我们必须等待原先的Leader恢复到可用状态。(高可用性和数据一致性的平衡)
关于unclean选举,不同的场景有不同的配置方式。对数据质量和数据一致性要求较高的系统会禁用这种unclean的leader选举(比如银行)。如果在可用性要求较高的系统里,比如实时点击流分析系统, 一般不会禁用unclean的leader选举。