我们知道kafka中hw可以用来管理消费者能访问到的最新的数据的位置, 并且当kafka leader节点挂掉后, follower节点会把hw以后的数据都清理掉, 从hw位置开始从新选举出来的leader节点同步数据, 那么HW增长的原理是怎样的呢? 带着这个疑问, 看完以下内容就能明白!
1. LEO (log end offset)是干啥的?
每个副本(leader/ follower)都有一个leo, 表示的是这个副本最新的数据最大的偏移量, 不包含当前数据
leo存储在哪里?存储在RAM也就是内存里...
2. HW (high watermarks)是什么? 有什么用?
最高水位线, 是一个Topic分区的偏移量, 消费者能够访问的最新的数据就是这个HW之前的数据
一个Topic多个分区, 每个分区的每个副本都有一个自己的HW
2.1 HW是谁来维护的呢? 是leader节点吗?
并不是Leader节点, 而是由Broker节点, 每个Broker节点管理自己上面的所有副本的HW然后把数据写入到本地文件中: (replication-offset-checkpoint)
2.2 HW记录存储在哪里?
每一个broker节点上, 都有一个文件(replication-offset-checkpoint)用来专门存储所有分区副本的HW, 每当HW增长之后, 就会修改这个文件. 数据形式是这样:
2.3 HW是怎样增长的?
我们把问题简单化, 如果一个Topic只有1个分区, 该分区一共有3个副本: 1个leader+2个follower, 三个副本, 都有自己的HW, 那么HW是怎样增长的呢?内部原理是怎样的?
1). 消息写入到Broker, 消费者会把写数据的请求发送给leader副本, 写入数据后leader的leo就会增加!
2). 两个follower副本会定期发送请求(FetchRequest)给leader副本, 来拉取数据, 发送的请求是: FetchRequest, 在发送的请求数据中, 会携带自身的LEO信息
3). leader收到FetchRequest会拿到所有副本的LEO数据, 取最小值: min(leader LEO, follower1 LEO, follower2 LEO) 赋值给leader的HW
4). 然后leader会把数据+HW信息封装在一起返回给follower: FetchResponce
5). follower拿到FetchResponce之后, 解析得到其中封装的数据, 以及HW, 就可以更新自己的HW和LEO
2.4 那上面例子中的两个Follower的HW会永远一样吗?
并不一定完全一样, 有可能会不一样, 取决于机器的性能, 写入速度等因素..
两个Follower都得到FetchResponce之后会解析, 然后更新自己的HW并写入数据, 之后又更新LEO, 如果1台节点性能好, 解析很快, 它会率先完成HW和LEO的增加, 直到它增加结束, f2也还没解析完FetchResponce, 此时就会造成HW在两台Follower节点不一致!
3. HW和LEO的关系是啥?
如下图, 可以看到HW和LEO的关系(↓)
hw<=leo
leader节点要等待follower发送ack回来(FetchRequest和ACK在一起)之后, hw才会增加, 而leo只要消息写入了当前副本里, 就会增加
hw和leo的偏移量, 都是不包含本身那个偏移量数据的. 都指向的是下一条数据.
4. ISR是啥?
ISR, 全称是:In Sync Replicas
4.1 ISR、OSR、AR 是什么?
ISR:In-Sync Replicas 副本同步队列, 存储的是运行正常的副本
OSR:Out-of-Sync Replicas 异常副本
AR:Assigned Replicas 所有副本
4.2 ISR里的节点遵循的是什么规则?
这个参数: replica.lag.time.max.ms 默认是10s , 意思就是如果一个follower节点落后的数据延迟, 超过10s钟, 就会踢出ISR
4.3 ISR有啥用?
ISR数量<=副本数量
是用来保证数据的可靠性用到的机制. 每个分区都有一份ISR列表.
防止有个别节点网络太差, 或者磁盘性能太差, 拖累了整体, 因为要等待所有节点都发送ACK确认之后, HW才能增加, 消费者才能看到数据.
里边包含了该分区的副本节点, 可能不是全部节点, 只有能快速从leader节点拉取数据并且一直保持心跳的节点才会在这个ISR里, 如果不在这个ISR里, 说明这个节点性能太差拉取数据太慢, 或者卡主了, 挂掉了之类的
注:
只有当ACK设置为-1的时候, ISR才有用, 当ack设置为-1时候, 消息写入kafka成功的标志是, ISR里的所有节点都写入成功, 而不是所有副本都写入成功!
4.4 一个分区的ISR信息存储在哪里?
每个分区都会维护一个ISR, 由分区的leader节点维护
ISR存储在Zookeeper里
get /brokers/topics/test/partitions/0/state #zookeeper中执行这个命令, 打印内容如下:
{"controller_epoch":10,"leader":0,"version":1,"leader_epoch":1,"isr":[0,1,2]} cZxid = 0x60000013c ctime = Sun Nov 28 21:17:46 CST 2021 mZxid = 0x60000027b mtime = Wed Dec 01 10:39:52 CST 2021 pZxid = 0x60000013c cversion = 0 dataVersion = 6 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 77 numChildren = 0