4. Kafka 高可用集群:从 Broker 部署到跨机房复制

Kafka 的高可用,说白了就是保证「数据不丢、服务不断」。我在多个企业的 CDC 项目中见过各种 Kafka 翻车现场——有的因为副本数配少了,一台 Broker 宕机直接丢分区;有的因为 ISR 机制没吃透,生产环境频繁「缩圈」导致写入超时。这一章,我把 Broker 集群部署、副本因子、ISR、Leader 选举、日志压缩和跨机房复制这几个核心点串起来讲,全是实战里踩过的坑。

4.1 Broker 集群部署:别在第一步就埋雷

部署 Kafka 集群,我个人的习惯是「先定规模,再定配置」。你想想看,如果一开始 Broker 数量就拍脑袋定,后面扩缩容会非常痛苦。

4.1.1 节点数量怎么定?

  • 最小集群:3 台 Broker。这是能容忍 1 台宕机的最小规模(配合副本因子 3)。
  • 生产推荐:5~7 台。既能保证多数派选举,又能承受滚动升级时的短暂失联。
  • 超大规模:超过 20 台时,建议按数据中心或业务域拆分集群,避免 Zookeeper 压力过大。
我的经验:曾经有个项目上了 15 台 Broker,但副本因子只配了 2。结果一台 Broker 磁盘故障,另一台刚好在 GC 停顿,分区直接不可用。所以节点数和副本因子要一起规划,别单独看数量。

4.1.2 关键配置清单

配置项 推荐值 说明
broker.id 0, 1, 2 ... 必须唯一,建议用数字序列,不要用 IP 最后一段
log.dirs /data1/kafka,/data2/kafka 多磁盘挂载,提升 IO 吞吐;我习惯至少 2 块盘
num.partitions 3~6(按吞吐量调) 默认值,创建 Topic 时可覆盖
default.replication.factor 3 生产环境不要低于 3
zookeeper.connect zk1:2181,zk2:2181,zk3:2181 至少 3 个 ZK 节点,避免单点
注意:broker.id 一旦确定,不要随意更改。Kafka 内部用 broker.id 识别节点,改了会导致分区副本重新分配,引发不必要的重平衡。

4.2 副本因子与 ISR 机制:数据安全的最后防线

副本因子决定了每个分区有多少份数据。ISR(In-Sync Replicas)则是「当前跟 Leader 保持同步的副本集合」。这两个概念必须一起理解。

4.2.1 副本因子怎么选?

  • 副本因子 = 1:数据无冗余,Broker 宕机即丢数据。仅用于开发测试。
  • 副本因子 = 2:能容忍 1 台宕机,但如果那台刚好是 Leader,且 Follower 落后太多,仍有丢数据风险。
  • 副本因子 = 3:生产标配。容忍 1 台宕机,且多数派选举时不会阻塞。
  • 副本因子 > 3:写入放大严重,一般用于金融、监管等极端场景。

4.2.2 ISR 的「缩圈」逻辑

ISR 不是一成不变的。Follower 如果长时间没有向 Leader 拉取数据(由 replica.lag.time.max.ms 控制,默认 30 秒),就会被踢出 ISR。为什么会这样?因为 Leader 要保证「写入了 ISR 中所有副本的数据才是已提交的」。如果某个 Follower 太慢,Leader 不能等它,否则写入延迟会飙升。

核心原则:只有 ISR 中的副本才有资格成为新 Leader。ISR 之外的副本,即使数据完整,也不能参与选举。

我在项目中遇到过一个问题:某个 Follower 因为网络抖动频繁进出 ISR,导致 Leader 不断调整 highWatermark,消费者端出现大量重复消费。后来把 replica.lag.time.max.ms 从 30 秒调到 60 秒,问题缓解了很多。嗯,这里要注意——调大这个值会降低数据可靠性,需要权衡。

4.2.3 min.insync.replicas 的陷阱

这个配置决定了「至少要有多少个 ISR 副本确认写入,才算成功」。如果 min.insync.replicas = 2,而当前 ISR 只有 1 个副本,写入就会报 NotEnoughReplicasException。

我曾经踩过的坑:把 min.insync.replicas 设成 3,但副本因子也是 3。结果一台 Broker 宕机后,ISR 只剩 2 个,所有写入全部失败。正确的做法是:min.insync.replicas 应该小于副本因子,比如副本因子 3 时,设成 2。

4.3 Leader 选举:谁说了算?

Kafka 的 Leader 选举依赖 Zookeeper 的临时节点和 Watch 机制。当一个 Leader 宕机时,Controller(由 ZK 选举产生)会从 ISR 中选出一个新 Leader。

4.3.1 选举流程

  1. Leader 宕机,ZK 上的临时节点消失。
  2. Controller 感知到变化,查询该分区的 ISR 列表。
  3. 从 ISR 中选出第一个副本作为新 Leader(按 broker.id 排序)。
  4. 新 Leader 开始接收读写请求,并更新 ZK 上的 Leader 信息。

4.3.2 如果 ISR 为空怎么办?

这是最危险的情况。如果所有副本都宕机了,Kafka 有两种策略:

  • 等待 ISR 中任意副本恢复:默认行为,保证数据一致性,但服务不可用。
  • 允许从非 ISR 副本选举:通过 unclean.leader.election.enable=true 开启。这会丢失数据,但能快速恢复服务。
我的建议:在 CDC 场景中,数据一致性通常比可用性更重要。我一般保持 unclean.leader.election.enable=false,宁可等几分钟,也不丢数据。但如果你的业务可以容忍少量数据丢失,比如日志采集,可以开启。

4.4 数据持久化与日志压缩

Kafka 的数据持久化不是简单的写文件。它用「分段日志 + 索引」的方式,实现了高效的读写和清理。

4.4.1 日志分段与清理策略

策略 配置 适用场景
基于时间 log.retention.hours 默认 7 天,适合大部分 CDC 场景
基于大小 log.retention.bytes 按磁盘容量控制,防止写满
日志压缩 cleanup.policy=compact 保留每个 Key 的最新值,适合状态同步

4.4.2 日志压缩的工作原理

日志压缩不是实时发生的。Kafka 后台有一个 Cleaner 线程,它会扫描日志段,对相同 Key 只保留最新的一条记录。你想想看,如果 CDC 同步的是数据库的变更日志,每条记录都有主键作为 Key,压缩后只保留每个主键的最新状态,这样消费者就能拿到「当前快照」,而不需要重放所有历史变更。

注意:日志压缩不能保证实时性。Cleaner 线程默认每 15 秒启动一次,而且只处理超过 log.cleaner.min.cleanable.ratio(默认 0.5)的脏数据比例。如果你的 Topic 写入量很大,压缩可能跟不上。

4.5 跨机房复制:MirrorMaker 2 实战

跨机房复制是 CDC 高可用的最后一块拼图。我参与过的一个金融项目,要求两个数据中心之间延迟不超过 5 秒,且数据不能丢。我们最终选了 MirrorMaker 2(MM2)。

4.5.1 MM2 的核心架构

MM2 本质上是一个 Kafka Connect 集群。它从源集群消费数据,然后写入目标集群。和旧版 MirrorMaker 相比,MM2 最大的改进是:

  • 自动创建 Topic:目标集群会自动创建与源集群同名的 Topic,并保持分区数一致。
  • 偏移量同步:通过内部 Topic mm2-offsets 记录消费进度,支持断点续传。
  • 双向复制:支持 Active-Active 模式,但需要处理数据冲突。

4.5.2 配置示例

# mm2.properties
clusters = source, target
source.bootstrap.servers = src-kafka1:9092,src-kafka2:9092
target.bootstrap.servers = tgt-kafka1:9092,tgt-kafka2:9092

source->target.enabled = true
source->target.topics = .*   # 复制所有 Topic

# 偏移量同步
sync.topic.acls.enabled = false
emit.checkpoints.enabled = true
checkpoints.topic.replication.factor = 3
我的经验:MM2 默认使用单线程消费,吞吐量有限。如果源集群写入量很大,可以开启 source->target.tasks.max=10 来增加并行度。但要注意,目标集群的写入压力也会随之增大。

4.5.3 跨机房复制的避坑指南

  • 网络延迟:跨机房带宽和延迟是硬约束。我曾经遇到过因为专线抖动,MM2 频繁重连,导致数据积压。后来加了重试和告警,才稳定下来。
  • 数据冲突:Active-Active 模式下,两个机房同时修改同一条数据,会导致冲突。MM2 没有内置冲突解决机制,需要业务层处理。
  • 监控:一定要监控 MM2 的 consumer lag 和 connector 状态。我习惯用 Prometheus + Grafana 做可视化,一旦 lag 超过阈值就告警。

4.6 本章知识体系总览

下面这张图把本章的核心逻辑串起来了。你可以看到,从 Broker 部署到跨机房复制,每一层都在解决「高可用」的不同维度问题。

Kafka 高可用集群知识体系 Kafka 高可用集群知识体系 Broker 集群部署 节点规划 / 配置清单 副本因子与 ISR 数据冗余 / 同步副本集 Leader 选举 Controller / ISR 选举 数据持久化 日志分段 / 清理策略 核心机制:ISR 维护 + 日志压缩 + 偏移量管理 min.insync.replicas / unclean.leader.election / log.cleanup.policy 跨机房复制:MirrorMaker 2 双向复制 / 偏移量同步 / 冲突处理 / 监控告警 目标:数据不丢 + 服务不断 + 跨机房容灾 每一层都依赖下一层:部署是基础,ISR 和选举是保障,日志压缩是效率,MM2 是扩展
本章小结:Kafka 高可用不是靠单一技术实现的。从 Broker 部署的节点规划,到副本因子和 ISR 的精细调优,再到 Leader 选举的容错策略,最后到跨机房复制的整体架构——每一层都有坑,每一层都需要根据业务场景做取舍。我个人觉得,理解 ISR 机制是掌握 Kafka 高可用的钥匙,而 MM2 则是把高可用从单机房扩展到多机房的桥梁。