副本与ISR设计
一个Kafka分区本质就是一个备份日志,即利用多份相同的备份共同提供冗余机制来保持系统高可用性。
这些备份在Kafka中被称为副本(replica)。Kafka把分区的所有副本均匀地分配到所有broker上。
并从这些副本中挑选一个作为leader副本对外提供服务,而其他副本被称为Follower副本,只能被动地向leader副本
请求数据,从而保持与leader副本的同步。
所谓ISR,就是Kafka集群动态维护的一组同步副本集合(in-sync replicas)。
每个topic分区都有自己的ISR列表,ISR中的所有副本都与leader保持同步状态,
leader副本总是包含在ISR中的,只有ISR中的副本才有资格被选举为leader。
而Producer写入一条kafka消息只有被ISR中的所有副本都接收到,才被视为已提交状态。
Follower副本同步
Follower副本只做一件事:向leader副本请求数据。
- 起始位移(base offset):表示该副本当前所含的第一条消息的offset。
- 高水印值(high watermark HW):副本高水印值,保存了该副本最新一条已提交消息的位移。leader分区的HW值决定了副本中已提交消息的范围
也确定了consumer能够获取的消息上限,超过HW值的所有消息都被视为未提交成功的,每个Follower副本都有HW值,但是只有leader副本的HW值
才能决定Clients能看到的消息数量。 - 日志末端位移(log end offset LEO):副本日志中下一条待写入消息的offset。所有副本都需要维护自己的LEO信息,每当leader副本接收到
Producer端推送的消息,它会更新自己的LEO,同样,Follower副本向leader副本请求数据后也会增加Follower自身的LEO。事实上只有ISR
中的所有副本都更新了对应的LEO后,leader副本才会向右移动HW值表名消息写入成功。
Follower/Leader副本同步流程
对于acks=-1的producer而言,只有完整地做完上面所有5步操作,producer才能正常返回,标志着这条消息发送成功。
ISR设计
1、0.9.0.0版本之前
Kafka提供了一个参数replica.lag.max.messages
用于控制Follower副本落后leader副本的消息数,一旦超过这个消息数,
则视为该Follower为不同步状态,从而需要被Kafka踢出ISR。
导致follower与leader不同步的原因:
- 请求速度追不上;
- follower进程卡住;
- 新创建的副本;
relica.lag.time.max.ms
用来检测第一种情况,另外提供参数replica.lag.time.max.ms
用于检测另外两种情况,若
follower副本无法再这个时间内向leader请求数据,则会被视为不同步,被踢出ISR。
缺陷
无法正确设置replica.lag.max.messages
参数,若消息消费者批次发送消息数超过这个参数值,就会出现这样的情况:
它们不断地被踢出ISR,然后重新加回ISR,造成了与leader不同步、再同步、再不同步。大大增加了开销。
并且这个参数是全局设置的,对于不同业务不同流量的topic也是不能同时适用的。
2、0.9.0.0版本之后
去掉replica.lag.max.messages
参数,统一改用relica.lag.time.max.ms
参数,即follower落后leader副本的事件
间隔,对于“请求速度追不上的情况”,检测机制也发生了变化——如果一个follower副本落后leader的时间持续性地超过这个参数值
那么该follower副本就是不同步的,只要不是持续性落后,就不会出现反复一进一出的现象。