Title

kafka12-控制器及可靠性保证

1 集群控制器

实际时是一个broker,负责leader分区选举

1.1 控制器选举

集群里第一个启动的broker在Zookeeper中创建临时节点 /controller

其他broker在该控制器节点创建Zookeeper watch对象,使用Zookeeper的监听机制接收该节点的变更

即:Kafka通过Zookeeper的分布式锁特性选举集群控制器。

每个新选出的控制器通过 Zookeeper 的条件递增操作获得一个全新的、数值更大的 controller epoch。其他 broker 在知道当前controller epoc 后,如果收到由控制器发出的包含较旧epoch的消 息,就会忽略它们,以防止“脑裂”。

1.2 控制器如何知道哪个broker宕机

集群控制器负责监听zookeeper下的ids节点,一旦节点子节点发送变化,集群控制器得到通知

1.3 . 控制器需要知道宕机的broker上负责的是哪些分区的Leader副本分区

zookeeper下的ids节点的数据包含主题,及主题下的ISR等信息。控制器遍历这些Follower副本分区,并确定谁应该成为新Leader分区,然后向所有包含新Leader 分区和现有Follower的 broker 发送请求。该请求消息包含了谁是新Leader副本分区以及谁是Follower 副本分区的信息。

随后,新Leader分区开始处理来自生产者和消费者的请求,而跟随者开始从新 Leader副本分区消费消息。 当控制器发现一个 broker 加入集群时,它会使用broker ID 来检查新加入的 broker 是否包含现有分区的副本。如果有,控制器就把变更通知发送给新加入的broker和其他broker新 broker上的副本分区开始从Leader分区那里消费消息,与Leader分区保持同步。

1.4 结论:

1. Kafka使用Zookeeper 的分布式锁选举控制器,并在节点加入集群或退出集群时通知控制器。 
2. 控制器负责在节点加入或离开集群时进行分区Leader选举。 
3. 控制器使用epoch来避免“脑裂”。“脑裂”是指两个节点同时认为自己是当前的控制器。

2 可靠性保证

2.1 概念

  1. 创建Topic的时候可以指定 --replication-factor 3 ,表示分区的副本数,不要超过broker的数量。
  2. Leader副本是负责读写的节点,而其他副本则是Follower。Producer只把消息发送到Leader, Follower定期地到Leader上Pull数据。
  3. ISR是Leader负责维护的与其保持同步的Replica列表,即当前活跃的副本列表。如果一个 Follow落后太多,Leader会将它从ISR中移除。落后太多意思是该分区的复制的消息Follow长时间没有向Leader发送fetch请求(参数: replica.lag.time.max.ms 默认值:10000)。
  4. 为了保证可靠性,可以设置acks=all 。Follower收到消息后,会像Leader发送ACK。一旦 Leader收到了ISR中所有Replica的ACK,Leader就commit,那么Leader就向Producer发送 ACK。(相应的缺点就是会导致效率变低)

2.2 副本的分配

当某个topic的 --replication-factor为N(N>1)时,每个Partition都有N个副本,称作replica。原则上是将replica均匀的分配到整个集群上。不仅如此,partition的分配也同样需要均匀分配,为了更好的负载均衡。

副本分配的三个目标:

1. 均衡地将副本分散于各个broker上 
2. 对于某个broker上分配的分区,它的其他副本在其他broker上
3.  如果所有的broker都有机架信息,尽量将分区的各个副本分配到不同机架上的broker。

在不考虑机架信息的情况下:

1. 第一个副本分区通过轮询的方式挑选一个broker,进行分配。该轮询从broker列表的随机位置进行轮询。 
2. 其余副本通过增加偏移进行分配

2.3 失效副本

2.3.1 判定

replica.lag.time.max.ms 默认大小为10000

当ISR中的一个Follower副本滞后Leader副本的时间超过参数 replica.lag.time.max.ms 指定的 、值时即判定为副本失效,需要将此Follower副本剔出除ISR。

具体实现原理:当Follower副本将Leader副本的LEO之前的日志全部同步时,则认为该Follower副本已经追赶上Leader副本,此时更新该副本的lastCaughtUpTimeMs标识。

Kafka的副本管理器(ReplicaManager)启动时会启动一个副本过期检测的定时任务,而这个定时任务会定时检查当前时间与副本的lastCaughtUpTimeMs差值是否大于参数 replica.lag.time.max.ms 指定的值。

Kafka源码注释中说明了一般有两种情况会导致副本失效:

  1. Follower副本进程卡住,在一段时间内没有向Leader副本发起同步请求,比如频繁的Full GC。
  2. Follower副本进程同步过慢,在一段时间内都无法追赶上Leader副本,比如IO开销过大。

如果通过工具增加了副本因子,那么新增加的副本在赶上Leader副本之前也都是处于失效状态的。

如果一个Follower副本由于某些原因(比如宕机)而下线,之后又上线,在追赶上Leader副本之前 也是出于失效状态。

2.4 副本复制

日志复制算法(log replication algorithm)必须提供的基本保证是,如果它告诉客户端消息已被 提交,而当前Leader出现故障,新选出的Leader也必须具有该消息。在出现故障时,Kafka会从挂掉 Leader的ISR里面选择一个Follower作为这个分区新的Leader。

什么情况下会导致一个副本与 leader 失去同步

  • 慢副本(Slow replica):follower replica 在一段时间内一直无法赶上 leader 的写进度。造 成这种情况的最常见原因之一是 follower replica 上的 I/O瓶颈,导致它持久化日志的时间比 它从 leader 消费消息的时间要长;
  • 卡住副本(Stuck replica):follower replica 在很长一段时间内停止从 leader 获取消息。 这可能是以为 GC 停顿,或者副本出现故障;
  • 刚启动副本(Bootstrapping replica):当用户给某个主题增加副本因子时,新的 follower replicas 是不同步的,直到它跟上 leader 的日志

当副本落后于 leader 分区时,这个副本被认为是不同步或滞后的。在Kafka中,副本的滞后于Leader是根据 replica.lag.time.max.ms 来衡量

如何确认某个副本处于滞后状态

通过 replica.lag.time.max.ms 来检测卡住副本(Stuck replica)在所有情况下都能很好地工 作。它跟踪 follower 副本没有向 leader 发送获取请求的时间,通过这个可以推断 follower 是否正常。 另一方面,使用消息数量检测不同步慢副本(Slow replica)的模型只有在为单个主题或具有同类流量模式的多个主题设置这些参数时才能很好地工作,但我们发现它不能扩展到生产集群中所有主题。

posted @ 2021-08-22 23:38  apeGcWell  阅读(79)  评论(0)    收藏  举报