【Kafka】ISR 高水位问题(一)

405 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

概念:

  • LEO(log end offset): 指代下次写入到此 Partition 的下一条数据的 offset, 是 partition 最大 offset+1
  • HW(High Water Mark):Leader partition 同步到其所有 followeroffset

按图解析:

2022-06-0217-45-07.png

  • offset = 0 ~ 14, LEO = 15:代表最后一条数据后面的 offset ,下一次将要写入的数据 offset
  • HW = 8offset = 0 ~ 7 已提交数据,offset = 8 ~ 14 未提交数据

LEO 作用:

  1. 负责推算 Leader partitionHW
  2. 更新 HW:当所有的 follower partitionLEO 推送给 Leader partition 时候,Leader partition 根据 min{LEO1...LEOn} 即可得到 LeaderHW

HW 作用:

  1. 更新 followerHW:当 follower 请求 leader 数据同步时候,leader 会返回自己的 HW, 然后 follower 会更新 min{Leader(HW),LEO}
  2. 划分已提交和未提交数据:HW=3,表示前3条数据是已经同步到其他所有的 follower 里面去了,所以也将其叫做 committed(已提交数据),消费者是消费不到 HW 之后的 uncommmitted 数据的
  3. 消费:Consumer 只能看到 base offsetHW offset 之间的数据,这部分数据是 committed,可以被消费。
# 默认10000 即 10秒
replica.lag.time.max.ms
   
​
# 允许 follower 副本落后 leader 副本的消息数量,超过这个数量后,follower 会被踢出 ISR
replica.lag.max.messages 

问题

(1)LeaderFollowerHWLEO 如何更新?

Leader 操作:

  • 维护所有 follower 的 LEO
  • 收到 follower 请求后,每次返回都会携带 HW
  • 更新 HW 取各 followerLEO 的最小值,即 min{LEO1...LEOn}
  • 更新 LEO 数据写入一条,此指针就往后移动

Follower 操作:

  • 定期Leader 发送 fetch 请求同步数据,每个请求都会携带自己的 LEO
  • 更新 LEO 每次同步数据到 follower,都会更新其 LEO
  • 更新 HW 计算方式是 min{Leader(HW), 自己的(LEO)}

举个栗子:

2022-06-0600-08-55.png

# 副本有 4 个,1 个 leader 和 3 个 follower
replication-factor = 4# 最小同步数为3,3个副本写入数据就认为写入成功
min.insync.replicas = 3

(2)在高水位 HW 机制下,Leader 切换时候会发生哪些问题?

会有两个主要问题:

  1. Leader 切换时发生数据丢失问题
  2. Leader 切换时发生数据不一致问题
Leader 切换时发生数据丢失问题

此问题发生概率极低。

问题重现流程主要是:

# 副本有 2 个,1 个 leader 和 1 个 follower
replication-factor = 2# 最小同步数为1,1个副本写入数据就认为写入成功
min.insync.replicas = 1
  1. LeaderFollower 同步数据
  2. Follower 宕机了,又重启了
  3. Leader宕机了,Follower 被选举成 Leader

问题重现详细流程:

  1. 假设一开始:LeaderLEO = 1, HW = 0FollowerLEO = 0, HW = 0
  2. 数据同步:Follower 发送 fetch 请求,Follower 写入数据,LeaderLEO = 1, HW = 0FollowerLEO = 1, HW = 0
  3. 数据同步:Follower 发送 fetch 请求,LeaderLEO = 1, HW = 0FollowerLEO = 1, HW = 0,这时候 FollowerHW = 1 还没更新
  4. 这时,Follower 宕机后重启,FollowerLEO 会根据 HW 自动调整为 0,并把那条数据从日志文件中删除
  5. 这时,Leader 宕机了,Follower 被选举为 Leader ,之后根据 Leader 来同步数据
Leader 切换时发生数据不一致问题

问题重现流程主要是:

# 副本有 2 个,1 个 leader 和 1 个 follower
replication-factor = 2# 最小同步数为1,1个副本写入数据就认为写入成功
min.insync.replicas = 1
  1. LeaderFollower 同步数据
  2. Follower 宕机了,又重启了
  3. Leader宕机了,Follower 被选举成 Leader
  4. 同步数据

问题重现详细流程:

  1. 假设一开始:LeaderLEO = 2, HW = 1FollowerLEO = 1, HW = 1
  2. 数据同步:Follower 发送 fetch 请求,Follower 写入数据,LeaderLEO = 2, HW = 1FollowerLEO = 1, HW = 1,还没同步完成
  3. 这时,Leader 宕机了后重启,Follower 被选举为 新Leader
  4. 这时,生产者发了一条新数据给 新LeaderLeaderLEO = 2, HW = 2FollowerLEO = 2, HW = 2,虽然两者 HW = 2,但数据不同。