此处内容来自书籍Apache Kafka 实战一书(作者胡夕)
1Kafka Zookeeper路径
Kafka中使用到的各个Zookeeper节点, 路径如下图,
即:
2副本和ISR
什么是分区?
Kafka分区本质上就是一个备份日志, 即利用多份相同的备份共同提供冗余来保持系统高可用性.
什么是副本?
为了保持高可用的备份就是副本.
什么是ISR?
ISR实际上就是Kafka集群动态维护的一组同步副本集合(in-sync replicas), 这句话可以读出来ISR是副本集合, 是与Leader保持同步的副本集合.
实际上每个topic分区(注意是每个分区) 都有自己的ISR列表, ISR的所有副本都与leader保持同步状态, leader副本总是包含在ISR中的, 只有ISR中的副本才有资格被选举为leader.
什么情况下消息才是已提交?
producer写入的消息只有被ISR中的所有副本都接受到才被看成是已提交状态.
高可用能力:
根据ISR的解释, 可以知道假设ISR集合有N个副本, 那么此分区最多可以忍受N-1个副本崩溃而不丢失已提交消息.
2.1 follower副本同步
leader副本对外提供服务(读写), follower副本仅仅只做向leader副本请求数据, 从而保持与leader副本的同步.
上图中的几个位移:
- 起始位移(base offset): 表示该副本当前所含第一条消息的offset
- 高水印值(high watermark, HW): 副本高水印值, 它保存了该副本最新一条已提交消息的位移.leader分区的HW值确定了Consumer能够获取的消息上线, 超过HW值的所有消息都被视为"未提交成功的消息", consumer是看不到的. 另外需要注意的是除了leader副本有HW值之外其他follower副本也都有HW值, 不过只有leader副本的HW值才能决定clients的consumer能够看到的消息数量罢了.
- 日志末端位移(log end offset, LEO): 副本日志下一条待写入消息的offset, 比如此处的LEO是10, 说明(0-9)这10条消息是写入的, 下一条消息写入的位移将是序号10. 只有ISR列表中的所有副本都更新了对应的LEO之后, leader副本才会向右移动HW值 表名消息写入成功.
上面可以看到HW和LEO这两个值很重要, 但是这两个值leader副本与follower副本更新的方式不太一样.
2.1.1 LEO更新机制
- 1 Leader副本端的LEO更新:
leader写log时就会自动更新它自己的LEO值. - 2 Follower更新LEO值:
follower副本只是被动地向leader副本请求数据, 具体表现为follower副本不停地向leader副本所在的broker发送FETCH请求, 一旦获取消息, 便写入自己的日志中进行备份.
Kafka针对follower副本LEO的更新有两部分:
- LEO值保存在follower副本所在broker的缓存上
- LEO值保存在leader副本所在broker的缓存上. 此处可以理解出leader副本所在机器的缓存上保存了该分区下所有follower副本的LEO属性值(当然也包括它自己的LEO)
之所以有两套是因为前者用于帮助follower副本自身更新HW值, 而同时还需要使用后者来确定leader副本的HW值即分区HW
(1)follower副本端的follower副本LEO何时更新?
在follower发送FETCH请求后, leader将数据返回给follower, 此时follower开始向底层log写数据, 从而自动更新其LEO值.
(2)leader副本端的follower副本LEO何时更新?
leader副本段的follower副本LEO的更新发生在leader处理follower FETCH请求时,一旦leader接收到follower发送的FETCH请求, 它首先会从自己的log中读取相应的数据, 但是在给follower返回数据之前它先会去更新follower的LEO(即上面所说的第二套LEO值)
2.1.2 HW更新机制
1 follower副本端更新HW
follower更新HW发生在其更新LEO之后, 一旦follower向log写完数据, 它就会尝试更新HW值. 具体算法即比较当前LEO值与FETCH响应中leader的HW值, 取两者之间的最小值作为新的HW值. 因此: 如果follower的LEO值超过了leader的HW值, 那么follower的HW值是不会越过leader HW值的.2 leader副本端更新HW
learder副本端的HW值很重要, 因为它直接影响了分区数据相对于consumer 客户端的可见性.
leader副本端的HW值的更新 分为正常情况与异常情况两种:
(1) 正常情况下的更新场景:
A, producer向leader副本写入消息时: 因为写入消息会更新leader的LEO,, 故有必要再查看HW值是否也需要更新
B, leader处理follower FETCH 请求时: 当leader处理follower的FETCH请求时, 首先会从底层的log读取数据, 之后再尝试更新分区HW值
(2)异常情况下的更新场景:
A, 副本成为leader副本时: 当某个副本成为分区的leader副本, Kafka会尝试更新分区HW. 毕竟分区leader都发生了变更, 这个副本的状态是一定要检查的.
B, broker出现崩溃导致副本被剔除ISR时: 若有broker崩溃, 则必须查看是否会波及此分区(有可能此分区leader就在这个broker上), 因此检查分区HW值是否需要更新是有必要的.