kafka数据复制与failover

1,223 阅读6分钟

目录

了解学习别人的方案,不仅仅是掌握技术,其实在处理自己系统的问题和设计时,也会获得启发。所以今天打算聊一下kafka是如何进行数据复制,和failover是如何处理的。从下面几个方面阐述一下:

  1. 如何propagate消息
  2. 何时对消息进行commit
  3. replica是如何进行恢复的
  4. replica全部宕机如何处理

如何propagate消息

如图,假设目前kafka集群有4个broker节点,运行3个topic,他们的副本数为2,在创建topic的时候,kafka会尽可能均匀的分配各个topic的partition,达到负载均衡的目的。
每个topic的partition会存在对应的副本,也就是replica,在读写数据的时候都是通过leader进行,而且只能通过leader进行,follower会周期性的到leader上去pull数据,其实也就类似于一个consumer的角色。

何时对消息进行commit

为什么要说commit呢,复制和消息的commit又有什么关系?
一般我们在做分布式的写的时候,会有同步复制,和异步复制两种方式:

同步复制:写完leader之后,同时也要保证follower写入完成,leader只要返回,
          就代表数据主副本都写入成功,可以保证强的一致性,但是会降低可用性。
异步复制:写完leader之后,leader就可以返回,告诉客户端数据写入成功,
          然后follower异步的从leader获取最新数据,可以是leader异步push,也可以是follower异步pull。

而kafka不完全是这两种方式的一种,kafka的leader会维护一个ISR列表,根据列表和producer的ack配置来决定leader何时commit; 只有commit的数据才可以被consumer消费。下面结合ISR和commit策略详细解释。

ISR

ISR(in-sync replica),顾名思义,这就是一个正在保持同步的副本列表;
它的特点是当一个follower比leader落后太多,或者过长时间没有发起向leader的同步请求,follower就会从ISR中剔除。

commit策略

kafka的server有下面两个配置,控制着何时剔除ISR中的replica。

# 副本同步延迟十秒剔除
replica.lag.time.max.ms=10000  
# 副本同步延迟消息数超过6000条剔除
replica.lag.max.messages=6000  

kafka的topic可以通过min.insync.replicas=1配置此topic最小的ISR列表数量。

最后结合producer配置request.require.acks控制commit,这个参数实际上有三种值可以设置,分别是0,1和all。

  1. 第一种选择是把参数设置成0

    kafkaProducer只要把消息发送出去,不管那条数据有没有在哪怕Partition Leader上落到磁盘,就不管他了,直接认为这个消息发送成功。如果你采用这种设置的话,那么你必须注意的一点是,可能你发送出去的消息还在半路。结果呢,Partition Leader所在Broker就直接挂了,然后结果你的客户端还认为消息发送成功了,此时就会导致这条消息就丢失了。

  2. 第二种选择是设置acks=1

    只要Partition Leader接收到消息而且写入本地磁盘了,就认为成功了,不管其他的Follower有没有同步过去这条消息了。这种设置其实是kafka默认的设置方式,也就是说默认情况下,要是不设置这个参数,只要Partition Leader写成功就算成功。但是这里有一个问题,万一Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了,此时也会导致这条消息丢失,因为客户端已经认为发送成功了。

  3. 最后一种情况就是设置为all

    Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。如果说Partition Leader刚接收到了消息,但是结果Follower没有收到消息,此时Leader宕机了,那么客户端会感知到这个消息没发送成功,他会重试再次发送消息过去。此时可能Partition 2的Follower变成Leader了,此时ISR列表里只有最新的这个Follower转变成的Leader了,那么只要这个新的Leader接收消息就算成功了。

  4. acks=all就代表数据一定不会丢失了吗

    当然不是,如果你的Partition只有一个副本,也就是一个Leader,任何Follower都没有,因为ISR里就一个Leader,他接收完消息后宕机,也会导致数据丢失。所以说,这个acks=all,必须跟ISR列表里至少有2个以上的副本配合使用,起码是有一个Leader和一个Follower才可以。 这样才能保证说写一条数据过去,一定是2个以上的副本都收到了才算是成功,此时任何一个副本宕机,不会导致数据丢失。

所以kafka不完全是同步复制和异步复制,通过server,topic,producer的结合配置可以让用户自己权衡数据一致性,可用性。

replica是如何进行恢复的

下面模拟一下整个流程:

  1. 假设我们一直在写数据,当前leader和各个follower的数据情况如下,leader(A)3条数据,follower(B)同步了2条,follower(C)同步了1条

    leader(A) follwer(B) follwer(C)
    msg1 msg1 msg1
    msg2 msg2
    msg3

    ISR列表为[A,B,C],leader(A)commit了msg1

  2. leader(A)挂了,B选举成新的leader,此时ISR列表为[B,C],那么等follower(c)同步完成msg2后leader(B)可以提交msg2,但是无法提交msg3

    leader(A) leader(B) follwer(C)
    msg1 msg1 msg1
    msg2 msg2 msg2
    msg3
  3. 随后数据继续写入

    leader(A) leader(B) follwer(C)
    msg1 msg1 msg1
    msg2 msg2 msg2
    msg3 msg4 msg4
    msg5 msg5
  4. 后来A启动了,truncate掉msg1后面未提交的数据,同步并追赶leader(B)中数据。此时ISR为[A,B,C]

    leader(A) leader(B) follwer(C)
    msg1 msg1 msg1
    msg2 msg2 msg2
    msg4 msg4 msg4
    msg5 msg5 msg5

replica全部宕机如何处理

可以选择是否使用ISR中的replica做为重启的leader,选择是与否也会带来不同的区别

  1. 等待ISR中任一个replica恢复后作为leader

     1)等待时间较长,可用性降低
     2)如果ISR中所有的replica都无法恢复,则该partition用不可用。
    
  2. 选择第一个恢复的replica作为leader,不一定在ISR中(默认配置)

     1)可能未包含之前leader提交过的消息,数据丢失
     2)可用性高
    

文章有任何问题欢迎留言,原创文章,码字不易,喜欢可以点赞关注。