06-14-A-Kafka集群运维与迁移实战详解
️ 关键词:集群规划 · Partition 重分配 · 副本均衡 · MirrorMaker2 · 跨集群迁移 · 双集群容灾 · 滚动升级 · KRaft 迁移 · 配额 Quota · 安全认证 SASL
📌 导读 :11 篇讲了高可用与调优的"配置面",本篇讲运维的"操作面"------集群怎么规划(Broker 数/Partition 数/磁盘)、扩容后怎么做 Partition 重分配(Kafka 扩容必须迁数据,和 RocketMQ 的本质区别)、副本 Leader 均衡、跨集群迁移的 MirrorMaker2 方案、双集群容灾(Active-Standby/Active-Active)、滚动升级与 ZooKeeper→KRaft 迁移、多租户配额(Quota)与 SASL 安全认证。这些是"书里不教、出事才懂"的运维实战------被问"Kafka 扩容后新 Broker 没流量怎么办"能讲出 reassign 限流迁移,被问"怎么迁移到新集群"能给出 MM2 的完整方案,被问"ZK 怎么迁 KRaft"能讲出四步流程。
📑 目录
- 06-14-A-Kafka集群运维与迁移实战详解
-
- [📖 术语速查表(每个词都用人话解释)](#📖 术语速查表(每个词都用人话解释))
- 一、集群规划与日常巡检
-
- [1.1 规划公式(承接 11 篇 4.4,运维视角细化)](#1.1 规划公式(承接 11 篇 4.4,运维视角细化))
- [1.2 日常巡检清单](#1.2 日常巡检清单)
- [二、扩容与 Partition 重分配](#二、扩容与 Partition 重分配)
-
- [2.1 为什么 Kafka 扩容必须迁数据(对比 RocketMQ)](#2.1 为什么 Kafka 扩容必须迁数据(对比 RocketMQ))
- [2.2 重分配三步曲](#2.2 重分配三步曲)
- [2.3 Leader 均衡](#2.3 Leader 均衡)
- 三、跨集群迁移:MirrorMaker2
-
- [3.1 MM2 架构与能力](#3.1 MM2 架构与能力)
- [3.2 迁移五阶段(对比 RocketMQ 双写方案)](#3.2 迁移五阶段(对比 RocketMQ 双写方案))
- [3.3 双集群容灾模式](#3.3 双集群容灾模式)
- [四、升级与 KRaft 迁移](#四、升级与 KRaft 迁移)
-
- [4.1 滚动升级流程](#4.1 滚动升级流程)
- [4.2 ZooKeeper → KRaft 迁移(3.x 主线任务)](#4.2 ZooKeeper → KRaft 迁移(3.x 主线任务))
- [五、多租户治理:Quota 与安全](#五、多租户治理:Quota 与安全)
-
- [5.1 配额(Quota)](#5.1 配额(Quota))
- [5.2 安全三件套](#5.2 安全三件套)
- 六、跑一遍:扩容重分配演练
-
- [6.1 模拟扩容:3 Broker → 4 Broker](#6.1 模拟扩容:3 Broker → 4 Broker)
- 七、总结
-
- [7.1 一张图回顾全文](#7.1 一张图回顾全文)
- [7.2 核心要点浓缩(十二条)](#7.2 核心要点浓缩(十二条))
📖 术语速查表(每个词都用人话解释)
| 术语 | 一句话白话解释 |
|---|---|
| Partition 重分配(reassign) | 把 Partition 的副本搬到别的 Broker------扩容后均衡数据的唯一手段(kafka-reassign-partitions.sh) |
| 限流迁移(throttle) | 重分配时的复制带宽限制(--throttle 50MB/s)------防止迁移流量打爆网卡影响业务 |
| preferred-replica-election | 首选副本选举------把 Leader 切回副本列表的第一个(均衡 Leader 分布,减少跨机架流量) |
| MirrorMaker2(MM2) | 官方跨集群复制工具------Topic/位点/配置自动同步,支持双活与迁移 |
| checkpoint | MM2 的位点映射文件------源集群 Offset ↔ 目标集群 Offset 的对照表(消费位点迁移用) |
| 滚动升级(Rolling Upgrade) | 逐台 Broker 升级重启------协议版本协商(13 篇)保证混跑期兼容 |
| ZK→KRaft 迁移 | 4 步:部署 Controller Quorum → 迁移元数据 → Broker 切 KRaft → 下线 ZK |
| Quota(配额) | 按 client.id/用户限制生产消费带宽与请求速率------多租户防"一家打爆全集群" |
| SASL/SCRAM | 用户名密码认证机制------SASL_SSL(加密+认证)生产标配 |
| ACL | 访问控制列表------kafka-acls.sh 按 用户+Topic+操作 授权 |
| Cruise Control | LinkedIn 开源的自动化集群均衡器------自动检测热点、生成并执行 reassign 方案 |
一、集群规划与日常巡检
1.1 规划公式(承接 11 篇 4.4,运维视角细化)
text
Broker 数 = max(吞吐需求 ÷ 单 Broker 能力, 存储需求 ÷ 单机磁盘, 3)
单 Broker 能力参考:SSD 顺序写 ~150MB/s 业务流量(留余量),千兆网卡 ~100MB/s 是瓶颈
例:500MB/s 写入 ×3 副本 = 1.5GB/s 集群写入 → 千兆网要 15 台起(万兆网 5~6 台)
Partition 总数红线:单 Broker ≤ 2000~4000(KRaft 前更严)
------Partition 多 = 文件句柄多 + 故障时 Leader 选举慢 + 端到端延迟升
磁盘 = 日写入 × 副本数 × 保留天数 × 1.3
JVM 堆 = 6GB 足够(别学"内存大就给堆"------PageCache 才是命脉,11 篇)
1.2 日常巡检清单
shell
# ① 集群健康三板斧
kafka-topics.sh --bootstrap-server b1:9092 --describe --under-replicated-partitions
# 输出为空 = 健康;有输出 = 副本掉队(11 篇 URP 告警的命令行版)
kafka-metadata.sh --snapshot ... --cluster-id ... # KRaft 元数据检查(3.x)
# 或 ZK 时代:echo stat | nc zk1 2181 | grep Mode # 确认 ZK leader/follower
# ② Leader 分布均衡检查
kafka-topics.sh --bootstrap-server b1:9092 --describe | grep Leader | sort | uniq -c
# 120 Leader: 1
# 118 Leader: 2
# 121 Leader: 3 ← 均衡;某台显著多 = 要 preferred-replica-election
# ③ 消费组 Lag 巡检(11 篇三章)
kafka-consumer-groups.sh --bootstrap-server b1:9092 --list
kafka-consumer-groups.sh --bootstrap-server b1:9092 --describe --group xxx
# ④ 磁盘与句柄
df -h /data/kafka-logs # 水位 75%/85% 两级告警
ls /proc/$(pgrep -f kafka.Kafka)/fd | wc -l # 文件句柄数(ulimit -n 要 ≥ 10 万)
二、扩容与 Partition 重分配
2.1 为什么 Kafka 扩容必须迁数据(对比 RocketMQ)
| RocketMQ | Kafka | |
|---|---|---|
| 扩容后 | 新消息自然流入新 Broker 组(存量不动) | 新 Broker 没有任何 Partition 副本------空转! |
| 原因 | Queue 按 Broker 分布,Topic 路由自动覆盖新组 | Partition 的副本列表是建 Topic 时静态分配的 |
| 动作 | 无需迁移(消息会过期) | 必须跑 reassign 把副本搬过去 |
根源 :Kafka 的 Partition 是"数据+副本位"的静态绑定,不会自动流动------扩容 ≠ 均衡,均衡要手动 reassign(这是 Kafka 运维和 RocketMQ 最大的操作差异)。
2.2 重分配三步曲
shell
# ① 生成方案:把指定 Topic 的副本重分配到新 Broker 列表
cat > topics.json <<'EOF'
{"topics": [{"topic": "user-behavior"}], "version": 1}
EOF
kafka-reassign-partitions.sh --bootstrap-server b1:9092 \
--topics-to-move-json-file topics.json \
--broker-list "1,2,3,4,5" \ # 新集群的完整 Broker 列表(含新加的 4,5)
--generate
# 输出 Proposed partition reassignment configuration(存成 reassign.json)
# ------生成后人工检查!别直接执行(方案可能把热点堆一台)
# ② 执行(带限流!)
kafka-reassign-partitions.sh --bootstrap-server b1:9092 \
--reassignment-json-file reassign.json \
--throttle 50000000 \ # 限流 50MB/s------防迁移打爆网卡
--execute
# ③ 验证进度(完成后必须移除限流!)
kafka-reassign-partitions.sh --bootstrap-server b1:9092 \
--reassignment-json-file reassign.json --verify
# Status of partition reassignment: completed
kafka-reassign-partitions.sh ... --verify # verify 成功会自动清 throttle
# 忘了清限流 = 后续所有副本同步都被限速 50MB/s(经典事故!)
四个军规:
- --generate 的方案要人工审查(或直接用 Cruise Control 自动生成+审查);
- 必须 --throttle(不限流的迁移能把业务流量挤死);
- verify 后确认限流已清除 (
kafka-configs --describe --entity-type topics查 leader.replication.throttled.rate); - 低峰期分批迁(一次一个 Topic,迁完观察再下一个)。
2.3 Leader 均衡
shell
# 重分配后 Leader 可能集中------执行首选副本选举把 Leader 打散
kafka-leader-election.sh --bootstrap-server b1:9092 \
--election-type PREFERRED --all-topic-partitions
# 或开自动:auto.leader.rebalance.enable=true(默认开,每 5min 检查)
三、跨集群迁移:MirrorMaker2
3.1 MM2 架构与能力
#mermaid-svg-xFawNodFZ3CrNySF{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xFawNodFZ3CrNySF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xFawNodFZ3CrNySF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xFawNodFZ3CrNySF .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-xFawNodFZ3CrNySF .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xFawNodFZ3CrNySF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xFawNodFZ3CrNySF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xFawNodFZ3CrNySF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xFawNodFZ3CrNySF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xFawNodFZ3CrNySF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xFawNodFZ3CrNySF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xFawNodFZ3CrNySF .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-xFawNodFZ3CrNySF .marker.cross{stroke:#0b0b0b;}#mermaid-svg-xFawNodFZ3CrNySF svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-xFawNodFZ3CrNySF p{margin:0;}#mermaid-svg-xFawNodFZ3CrNySF .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-xFawNodFZ3CrNySF .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xFawNodFZ3CrNySF .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xFawNodFZ3CrNySF .cluster-label span p{background-color:transparent;}#mermaid-svg-xFawNodFZ3CrNySF .label text,#mermaid-svg-xFawNodFZ3CrNySF span{fill:#333;color:#333;}#mermaid-svg-xFawNodFZ3CrNySF .node rect,#mermaid-svg-xFawNodFZ3CrNySF .node circle,#mermaid-svg-xFawNodFZ3CrNySF .node ellipse,#mermaid-svg-xFawNodFZ3CrNySF .node polygon,#mermaid-svg-xFawNodFZ3CrNySF .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-xFawNodFZ3CrNySF .rough-node .label text,#mermaid-svg-xFawNodFZ3CrNySF .node .label text,#mermaid-svg-xFawNodFZ3CrNySF .image-shape .label,#mermaid-svg-xFawNodFZ3CrNySF .icon-shape .label{text-anchor:middle;}#mermaid-svg-xFawNodFZ3CrNySF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xFawNodFZ3CrNySF .rough-node .label,#mermaid-svg-xFawNodFZ3CrNySF .node .label,#mermaid-svg-xFawNodFZ3CrNySF .image-shape .label,#mermaid-svg-xFawNodFZ3CrNySF .icon-shape .label{text-align:center;}#mermaid-svg-xFawNodFZ3CrNySF .node.clickable{cursor:pointer;}#mermaid-svg-xFawNodFZ3CrNySF .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-xFawNodFZ3CrNySF .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-xFawNodFZ3CrNySF .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-xFawNodFZ3CrNySF .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-xFawNodFZ3CrNySF .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-xFawNodFZ3CrNySF .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-xFawNodFZ3CrNySF .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-xFawNodFZ3CrNySF .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-xFawNodFZ3CrNySF .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-xFawNodFZ3CrNySF .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xFawNodFZ3CrNySF .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xFawNodFZ3CrNySF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xFawNodFZ3CrNySF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xFawNodFZ3CrNySF rect.text{fill:none;stroke-width:0;}#mermaid-svg-xFawNodFZ3CrNySF .icon-shape,#mermaid-svg-xFawNodFZ3CrNySF .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-xFawNodFZ3CrNySF .icon-shape p,#mermaid-svg-xFawNodFZ3CrNySF .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-xFawNodFZ3CrNySF .icon-shape .label rect,#mermaid-svg-xFawNodFZ3CrNySF .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-xFawNodFZ3CrNySF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xFawNodFZ3CrNySF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xFawNodFZ3CrNySF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 目标集群 B
MM2 集群
独立部署,Connect 框架
源集群 A
监控
Topic:order-event。
MirrorSourceConnector。
复制消息(批量 + 压缩)。
MirrorCheckpointConnector。
位点映射(checkpoint)。
MirrorHeartbeatConnector。
集群心跳 / 延迟监控。
Topic:A.order-event。
默认加源集群前缀防循环。
MM2 自动同步的内容 :Topic 数据 + Topic 配置 (保留期/分区数)+ 消费位点映射(checkpoint)+ ACL------比老 MirrorMaker(只搬消息)完整一个量级。
3.2 迁移五阶段(对比 RocketMQ 双写方案)
text
阶段0:目标集群就绪 + MM2 部署(A→B 全量 Topic 复制)
阶段1:追平验证------MM2 复制 Lag < 秒级,checkpoint 正常
阶段2:消费端灰度切换------
读 B 集群(Topic 名带 A. 前缀,或用 --replication-policy 去掉前缀)
位点用 checkpoint 翻译(不用从头消费!)
阶段3:生产端切换------Producer 改连 B 集群(或 DNS/VIP 切换)
此刻 MM2 反向部署(B→A)作为回滚通道
阶段4:观察期(A 集群只读保留 1~2 周)→ 下线 A + 撤 MM2
与 RocketMQ 迁移方案对比(06-06-A 篇 3.1):
| 维度 | Kafka MM2 | RocketMQ 双写/Replicator |
|---|---|---|
| 位点迁移 | checkpoint 自动翻译(消费进度无损切换) | 按时间重置位点(粗略) |
| 业务侵入 | 无(复制层独立部署) | 双写要改代码 / Replicator 无侵入 |
| 回滚 | 反向 MM2 | 旧集群只读保留 |
| 防循环复制 | Topic 前缀(A.order-event)天然防环 | 要手动配置排除 |
3.3 双集群容灾模式
| 模式 | 做法 | RPO/RTO | 适用 |
|---|---|---|---|
| Active-Standby | MM2 单向复制,灾备集群平时不服务 | RPO=复制延迟(秒级),RTO=分钟(切 DNS+位点翻译) | 异地容灾主流 |
| Active-Active | MM2 双向复制(前缀防环),两集群都读写 | RPO≈秒级,RTO≈0 | 同城双活(要处理"消费自己复制回来的消息"去重) |
| Stretch 集群 | 单集群跨机房(Broker 分布两机房) | RPO=0 | 不推荐(跨机房 ISR 同步延迟拖垮写入) |
四、升级与 KRaft 迁移
4.1 滚动升级流程
text
① 读 Release Note:inter.broker.protocol.version / log.message.format.version 兼容矩阵
② 逐台升级(每次一台):
controlled shutdown(kafka-server-stop.sh 会优雅移交 Leader)
→ 升级二进制 → 改配置(protocol.version 先保持旧值!)→ 启动
→ 等 ISR 全部追平(URP=0)再升下一台
③ 全部升完:统一把 inter.broker.protocol.version 改成新版本,再滚一遍
------"先升二进制后升协议"保证任何时刻可回滚
④ 客户端 SDK 按需升级(服务端向后兼容旧客户端,13 篇 ApiVersions)
4.2 ZooKeeper → KRaft 迁移(3.x 主线任务)
text
四步(KIP-866):
① 部署 Controller Quorum(3/5 个独立 Controller 节点,KRaft 模式)
② 迁移元数据:ZK 里的 Topic/ACL/配置 → KRaft 元数据日志
(kafka-metadata.sh 迁移工具,双写期两边一致)
③ Broker 逐台滚动重启为 KRaft 模式(zk.connect 配置移除)
④ 验证后下线 ZooKeeper 集群
注意:3.5 前只支持新集群用 KRaft;存量 ZK 集群迁移要 3.6+(生产建议 3.7+)
回滚窗口:②③阶段可回退 ZK;④下线后不可逆
五、多租户治理:Quota 与安全
5.1 配额(Quota)
shell
# 按 client.id 限流:某业务的生产带宽 ≤ 20MB/s,消费 ≤ 50MB/s
kafka-configs.sh --bootstrap-server b1:9092 --alter \
--add-config 'producer_byte_rate=20971520,consumer_byte_rate=52428800' \
--entity-type clients --entity-name log-collector
# 按用户限流(配合 SASL):
kafka-configs.sh ... --entity-type users --entity-name team-bigdata
# 请求速率配额(防元数据请求风暴):
--add-config 'request_percentage=20' # 该客户端最多占 20% 请求处理时间
超限行为 :Broker 不拒绝而是"延迟响应"(throttle_time_ms)------客户端被拖慢但不断连(软限流,比硬拒绝优雅)。
多租户三层次 (对比 RocketMQ 06-06-A 篇 5.2):Topic 命名规范({团队}.{域}.{用途})→ Quota+ACL(软隔离)→ 独立集群(硬隔离,核心业务标配)。
5.2 安全三件套
properties
# ① 认证:SASL_SSL + SCRAM-SHA-512(用户名密码)
listeners=SASL_SSL://:9093
sasl.enabled.mechanisms=SCRAM-SHA-512
# 创建用户:
# kafka-configs.sh --zookeeper/... --alter --add-config 'SCRAM-SHA-512=[password=xxx]' --entity-type users --entity-name order-service
# ② 加密:SSL 证书(内网可用 SASL_PLAINTEXT 省证书,跨公网必须 SSL)
# ③ 授权:ACL
kafka-acls.sh --bootstrap-server b1:9093 --command-config client.properties \
--add --allow-principal User:order-service \
--operation Write --topic order-event # 只能写
kafka-acls.sh ... --add --allow-principal User:point-service \
--operation Read --topic order-event --group point-group # 只能读该组
# 全局开关:authorizer.class.name=...StandardAuthorizer(KRaft)/ KafkaAuthorizer(ZK)
# 超级用户:super.users=User:admin(运维账号)
最小权限军规 :生产服务只给 Write,消费服务只给 Read+指定 Group------和 RocketMQ ACL(06-06-A 篇 5.1)同一原则。
六、跑一遍:扩容重分配演练
6.1 模拟扩容:3 Broker → 4 Broker
shell
# ① 现状:Topic 3 个 Partition 都在 Broker 1/2/3
kafka-topics.sh --bootstrap-server b1:9092 --describe --topic user-behavior
# Topic: user-behavior Partition: 0 Leader: 1 Replicas: 1,2 Isr: 1,2
# Topic: user-behavior Partition: 1 Leader: 2 Replicas: 2,3 Isr: 2,3
# Topic: user-behavior Partition: 2 Leader: 3 Replicas: 3,1 Isr: 3,1
# ← Broker 4 刚加入,没有任何副本(空转)
# ② 生成含 Broker 4 的重分配方案
kafka-reassign-partitions.sh --bootstrap-server b1:9092 \
--topics-to-move-json-file topics.json --broker-list "1,2,3,4" --generate
② 的输出(Current 是现状,Proposed 是方案------人工确认后执行):
json
Current partition replica assignment
{"version":1,"partitions":[{"topic":"user-behavior","partition":0,"replicas":[1,2],"log_dirs":["any","any"]},...]}
Proposed partition reassignment configuration
{"version":1,"partitions":[
{"topic":"user-behavior","partition":0,"replicas":[4,1],"log_dirs":["any","any"]},
{"topic":"user-behavior","partition":1,"replicas":[1,2],"log_dirs":["any","any"]},
{"topic":"user-behavior","partition":2,"replicas":[2,4],"log_dirs":["any","any"]}]}
shell
# ③ 限流执行 + 验证
kafka-reassign-partitions.sh --bootstrap-server b1:9092 \
--reassignment-json-file reassign.json --throttle 50000000 --execute
# 输出:Warning: You must run the --verify option periodically...(提醒你回来验证!)
kafka-reassign-partitions.sh --bootstrap-server b1:9092 \
--reassignment-json-file reassign.json --verify
# Status of partition reassignment:
# Reassignment of partition user-behavior-0 is completed.
# Reassignment of partition user-behavior-2 is still in progress. ← 等它 completed
# Throttle was removed. ← 限流自动清除(关键!)
# ④ 最终状态:Broker 4 已持有副本
kafka-topics.sh --bootstrap-server b1:9092 --describe --topic user-behavior
# Partition: 0 Leader: 4 Replicas: 4,1 Isr: 4,1
# Partition: 2 Leader: 2 Replicas: 2,4 Isr: 2,4
💡 对照理解 :①的"Broker 4 空转"就是 2.1 节"Kafka 扩容必须迁数据"的直观体现(对比 RocketMQ 加组即分流);③的
Throttle was removed是军规 3 的自动化兜底------但老版本不会自动清,verify 后必须手动确认限流已移除(忘了清 = 集群副本同步永远被限速,主从延迟告警不断,这是 Kafka 运维 Top3 事故源)。
七、总结
7.1 一张图回顾全文
#mermaid-svg-xGhQsx4Ig03MmsW4{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xGhQsx4Ig03MmsW4 .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-xGhQsx4Ig03MmsW4 .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xGhQsx4Ig03MmsW4 .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-xGhQsx4Ig03MmsW4 .marker.cross{stroke:#0b0b0b;}#mermaid-svg-xGhQsx4Ig03MmsW4 svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-xGhQsx4Ig03MmsW4 p{margin:0;}#mermaid-svg-xGhQsx4Ig03MmsW4 .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-xGhQsx4Ig03MmsW4 .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xGhQsx4Ig03MmsW4 .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xGhQsx4Ig03MmsW4 .cluster-label span p{background-color:transparent;}#mermaid-svg-xGhQsx4Ig03MmsW4 .label text,#mermaid-svg-xGhQsx4Ig03MmsW4 span{fill:#333;color:#333;}#mermaid-svg-xGhQsx4Ig03MmsW4 .node rect,#mermaid-svg-xGhQsx4Ig03MmsW4 .node circle,#mermaid-svg-xGhQsx4Ig03MmsW4 .node ellipse,#mermaid-svg-xGhQsx4Ig03MmsW4 .node polygon,#mermaid-svg-xGhQsx4Ig03MmsW4 .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .rough-node .label text,#mermaid-svg-xGhQsx4Ig03MmsW4 .node .label text,#mermaid-svg-xGhQsx4Ig03MmsW4 .image-shape .label,#mermaid-svg-xGhQsx4Ig03MmsW4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-xGhQsx4Ig03MmsW4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .rough-node .label,#mermaid-svg-xGhQsx4Ig03MmsW4 .node .label,#mermaid-svg-xGhQsx4Ig03MmsW4 .image-shape .label,#mermaid-svg-xGhQsx4Ig03MmsW4 .icon-shape .label{text-align:center;}#mermaid-svg-xGhQsx4Ig03MmsW4 .node.clickable{cursor:pointer;}#mermaid-svg-xGhQsx4Ig03MmsW4 .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-xGhQsx4Ig03MmsW4 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-xGhQsx4Ig03MmsW4 .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-xGhQsx4Ig03MmsW4 .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-xGhQsx4Ig03MmsW4 .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-xGhQsx4Ig03MmsW4 .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xGhQsx4Ig03MmsW4 .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-xGhQsx4Ig03MmsW4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xGhQsx4Ig03MmsW4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xGhQsx4Ig03MmsW4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-xGhQsx4Ig03MmsW4 .icon-shape,#mermaid-svg-xGhQsx4Ig03MmsW4 .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-xGhQsx4Ig03MmsW4 .icon-shape p,#mermaid-svg-xGhQsx4Ig03MmsW4 .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-xGhQsx4Ig03MmsW4 .icon-shape .label rect,#mermaid-svg-xGhQsx4Ig03MmsW4 .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-xGhQsx4Ig03MmsW4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xGhQsx4Ig03MmsW4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xGhQsx4Ig03MmsW4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Kafka 集群运维与迁移
规划与巡检。
Broker 数=max(吞吐,存储,3)
单 Broker Partition ≤2000~4000
巡检三板斧:URP/Leader 均衡/Lag
+磁盘水位+文件句柄。
扩容重分配。
Kafka 扩容必须 reassign(对比 RocketMQ 自然流入)
三步:generate 审查→throttle 执行→verify 清限流
忘清限流=Top3 事故源
Leader 均衡:preferred-replica-election。
跨集群迁移。
MM2:数据+配置+位点 checkpoint 自动同步
Topic 前缀防循环复制
五阶段:追平→切消费→切生产→反向 MM2 回滚→观察
容灾:Active-Standby 主流,双活要去重。
升级与治理。
滚动升级:先二进制后协议版本
ZK→KRaft 四步(3.6+,下线 ZK 不可逆)
Quota 软限流(延迟响应不断连)
SASL_SSL+ACL 最小权限。
7.2 核心要点浓缩(十二条)
- 规划红线:单 Broker Partition ≤2000~4000、JVM 堆 6GB 足够(PageCache 是命脉)、千兆网下单机 ~100MB/s 是吞吐上限。
- 巡检三板斧 :URP(副本掉队)、Leader 分布均衡、消费 Lag------加磁盘水位与文件句柄(Partition 多=句柄多)。
- Kafka 扩容必须迁数据 :新 Broker 不会自动获得副本(静态分配)------对比 RocketMQ"新水入新渠",这是两者运维的最大差异。
- reassign 三步曲 :generate(方案要人工审查 )→ execute(必须 --throttle )→ verify(确认限流已清除)。
- 忘清限流 = Top3 事故源 :所有副本同步被限速 → ISR 频繁收缩 → URP 告警不断------verify 后必查 throttled.rate。
- Leader 均衡 :preferred-replica-election 把 Leader 切回首选副本------减少跨机架流量+写入均衡。
- MM2 三 Connector :Source(消息)+ Checkpoint(位点翻译,消费进度无损切换 )+ Heartbeat(延迟监控)------Topic 前缀天然防循环复制。
- 迁移五阶段 :追平验证→灰度切消费(checkpoint 翻译位点)→切生产→反向 MM2 做回滚通道→观察期后下线。
- 容灾模式 :Active-Standby(MM2 单向,主流)、Active-Active(双向+去重)、Stretch 单集群跨机房(不推荐,ISR 跨机房拖垮写入)。
- 滚动升级军规 :先升二进制(protocol.version 保持旧值)→ 全部升完再升协议版本------任何时刻可回滚;controlled shutdown 优雅移交 Leader。
- ZK→KRaft 四步 :部署 Controller Quorum→迁元数据→Broker 滚动切换→下线 ZK(不可逆点)------存量集群要 3.6+。
- 多租户治理 :Quota 软限流(延迟响应不断连)+ SASL_SSL 认证 + ACL 最小权限(Write/Read 分开)------核心业务独立集群硬隔离。
📌 最后一句话 :Kafka 运维的核心认知是"数据是静态绑定的,流动要手动 "------Partition 不会自己搬家(reassign)、Leader 不会自己均衡(election)、集群不会自己复制(MM2)。这给了运维完全的控制力 (每一步可审查可限流可回滚),也意味着每个"以为会自动发生"的事都要写进操作手册。和 RocketMQ"流水自动分流"的运维哲学相比,Kafka 更像"管理一个分布式文件系统"------工具链(reassign/MM2/Cruise Control)用熟了,控制力就是生产力。
📌 配套阅读:
如果这篇文章对你有帮助,欢迎点赞、收藏、关注!