一台Broker凌晨挂了,消息还在不在?——副本机制和ISR详解
本文目录
先说结论
Kafka通过多副本(Replica)保证高可用:每个Partition有多个副本分布在不同Broker上,一个是Leader(负责读写),其余是Follower(被动同步)。Leader挂了,ISR列表里的Follower会被选为新Leader,消息不丢、服务不断。
面试核心三个概念:Leader/Follower角色分工、ISR(In-Sync Replicas)同步机制、Leader选举过程。把这三个串清楚,这道题就稳了。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
在某元宇宙社交公司做实时数仓时,有一次凌晨3点收到报警:Broker-2磁盘告警,运维说需要下线维护。我第一反应就是:上面的Partition Leader会不会丢消息?Flink消费会不会中断?下游Doris实时大盘能不能扛住?这些问题的答案全在Kafka的副本机制里。面试官问这道题,就是想看你对Kafka高可用的理解有多深。
Leader和Follower的分工
| 角色 | 职责 | 数量 | 关键细节 |
|---|---|---|---|
| Leader | 处理所有读写请求 | 每个Partition 1个 | Producer写Leader,Consumer也读Leader |
| Follower | 被动从Leader拉取数据 | replication.factor-1个 | 不处理外部读写,纯备份 |
注意一个关键区别:Kafka的Follower不像MySQL从库那样可以分担读流量。所有读写都走Leader,Follower纯粹做数据备份。好处是不用考虑读写分离带来的延迟不一致问题,设计简单可靠。
# 查看Partition的副本分布
kafka-topics.sh --bootstrap-server broker1:9092 \
--describe --topic gift_txn
# 输出示例(3 Broker + replication.factor=3):
# Topic: gift_txn Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0
# Topic: gift_txn Partition: 1 Leader: 2 Replicas: 2,0,1 Isr: 2,0,1
# Topic: gift_txn Partition: 2 Leader: 0 Replicas: 0,1,2 Isr: 0,1,2
#
# Leader分散在不同Broker上 → 负载均衡
# Replicas: 所有副本列表 Isr: 当前同步正常的副本
# 如果Isr比Replicas少,说明有Follower掉队了
ISR机制——Kafka可靠性的核心
ISR(In-Sync Replicas)是'当前和Leader保持同步的副本集合'。Follower持续从Leader拉取数据,如果拉取速度跟不上(超时或落后太多),就会被踢出ISR变成OSR(Out-of-Sync Replicas)。追上了就重新加入ISR。
# 核心参数:replica.lag.time.max.ms(默认30秒)
# Follower超过这个时间没向Leader发fetch请求
# 或fetch到的数据落后Leader超过这个时间 → 被踢出ISR
replica.lag.time.max.ms=30000
# ISR和acks的关系(第2篇讲过):
# acks=all等的就是ISR里所有副本的确认
# ISR越小 → acks=all的安全性越低
# 所以要配合min.insync.replicas使用
#
# 完整安全链:acks=all + min.insync.replicas=2 + replication.factor=3
Leader选举:Leader挂了怎么办?
当Leader所在的Broker宕机时,Controller(集群里负责管理的特殊Broker)会从ISR列表中选一个Follower做新Leader。流程如下:
# Leader选举过程
#
# 1. Broker-2宕机,上面有3个Partition的Leader
# 2. Controller检测到Broker-2下线(通过ZK或KRaft心跳)
# 3. 对每个受影响的Partition:
# a. 从ISR列表中选第一个存活的副本作为新Leader
# b. 更新元数据,通知所有Broker
# c. Producer/Consumer自动感知新Leader
# 4. 整个选举过程通常在毫秒到秒级完成
#
# 选举策略:
# - 默认只从ISR中选(unclean.leader.election.enable=false)
# - 如果ISR为空?宁可Partition不可用也不选OSR的副本
# - 原因:OSR的数据可能落后,选它当Leader会丢数据
unclean选举:数据一致性 vs 可用性的抉择
如果ISR列表空了(所有同步副本都挂了),有两个选择:
| 配置 | 行为 | 数据安全 | 可用性 |
|---|---|---|---|
| unclean.leader.election.enable=false(默认) | Partition不可用,等ISR恢复 | ✅ 不丢数据 | ❌ 暂时不可写 |
| unclean.leader.election.enable=true | 选OSR的副本当Leader | ❌ 可能丢数据 | ✅ 持续可用 |
我的实际选择:在元宇宙社交公司,交易类Topic(gift_txn)设false,宁可停写也不丢交易数据;行为日志Topic可以设true,保可用性优先。不同Topic不同策略,这是面试加分点。
实战踩坑:Broker下线引发的连锁反应
回到开头说的场景。凌晨Broker-2磁盘告警要下线,上面有6个Partition的Leader。我当时的处理流程:
① 先检查ISR:用kafka-topics.sh --describe确认所有受影响Partition的ISR至少还有2个副本在其他Broker上。确认OK。
② 优雅下线:不是直接kill,而是用kafka-server-stop.sh优雅关闭。Kafka会先把该Broker上的Leader转移到ISR中的其他Broker,再关闭进程。这样Consumer几乎无感知。
③ 观察Flink消费:通过Know Streaming确认Flink的Consumer Lag没有飙升,说明Leader切换成功,消费没中断。
④ 维护后重新上线:磁盘换完后启动Broker-2,它会自动从新Leader同步数据,追上后重新加入ISR。
整个过程业务无感知。这就是3副本+ISR机制的威力——任何单点故障都不影响服务。
面试高频追问
追问一:Follower怎么从Leader同步数据?
Follower主动向Leader发送Fetch请求,拉取新数据追加到自己的Log。和Consumer的消费机制类似,都是Pull模式。每个Follower维护自己的LEO(Log End Offset),当LEO追上Leader的LEO,就认为是同步的。
追问二:什么是HW(High Watermark)?
HW是ISR中所有副本都已同步到的最高offset。Consumer只能读到HW之前的消息。这保证了即使Leader切换,Consumer也不会读到还没同步到新Leader的数据。HW = min(ISR中所有副本的LEO)。
追问三:Controller是什么?怎么选的?
Controller是集群中负责管理Partition状态和Leader选举的特殊Broker。同一时间只有一个Controller。在ZK模式下通过抢注ZK临时节点选举;KRaft模式下通过Raft协议选举。Controller挂了会自动选新的。
总结
副本机制面试抓住三条线:① Leader/Follower分工(所有读写走Leader,Follower纯备份);② ISR同步机制(什么时候踢出、什么时候加回、和acks=all的关系);③ Leader选举(从ISR选、unclean选举的取舍)。如果能结合实际场景讲Broker下线时的处理流程,面试官会觉得你不只懂原理,还有生产环境的实操经验。
下一篇聊一个很多人答不好的题:Kafka能保证消息不丢不重吗?Exactly-Once到底怎么实现的?
你们生产环境Kafka的replication.factor设的几?有没有经历过Leader切换?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长
Kafka 面试通关手册
第11-15篇:格式选型、监控运维与数据治理
Wood聊大数据
9年大数据老兵,聊技术、聊职场、聊成长