06-14-A-Kafka集群运维与迁移实战详解

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(经典事故!)

四个军规:

  1. --generate 的方案要人工审查(或直接用 Cruise Control 自动生成+审查);
  2. 必须 --throttle(不限流的迁移能把业务流量挤死);
  3. verify 后确认限流已清除 (kafka-configs --describe --entity-type topics 查 leader.replication.throttled.rate);
  4. 低峰期分批迁(一次一个 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 核心要点浓缩(十二条)

  1. 规划红线:单 Broker Partition ≤2000~4000、JVM 堆 6GB 足够(PageCache 是命脉)、千兆网下单机 ~100MB/s 是吞吐上限。
  2. 巡检三板斧 :URP(副本掉队)、Leader 分布均衡、消费 Lag------加磁盘水位与文件句柄(Partition 多=句柄多)。
  3. Kafka 扩容必须迁数据 :新 Broker 不会自动获得副本(静态分配)------对比 RocketMQ"新水入新渠",这是两者运维的最大差异。
  4. reassign 三步曲 :generate(方案要人工审查 )→ execute(必须 --throttle )→ verify(确认限流已清除)。
  5. 忘清限流 = Top3 事故源 :所有副本同步被限速 → ISR 频繁收缩 → URP 告警不断------verify 后必查 throttled.rate。
  6. Leader 均衡 :preferred-replica-election 把 Leader 切回首选副本------减少跨机架流量+写入均衡。
  7. MM2 三 Connector :Source(消息)+ Checkpoint(位点翻译,消费进度无损切换 )+ Heartbeat(延迟监控)------Topic 前缀天然防循环复制。
  8. 迁移五阶段 :追平验证→灰度切消费(checkpoint 翻译位点)→切生产→反向 MM2 做回滚通道→观察期后下线。
  9. 容灾模式 :Active-Standby(MM2 单向,主流)、Active-Active(双向+去重)、Stretch 单集群跨机房(不推荐,ISR 跨机房拖垮写入)。
  10. 滚动升级军规 :先升二进制(protocol.version 保持旧值)→ 全部升完再升协议版本------任何时刻可回滚;controlled shutdown 优雅移交 Leader。
  11. ZK→KRaft 四步 :部署 Controller Quorum→迁元数据→Broker 滚动切换→下线 ZK(不可逆点)------存量集群要 3.6+。
  12. 多租户治理 :Quota 软限流(延迟响应不断连)+ SASL_SSL 认证 + ACL 最小权限(Write/Read 分开)------核心业务独立集群硬隔离。

📌 最后一句话 :Kafka 运维的核心认知是"数据是静态绑定的,流动要手动 "------Partition 不会自己搬家(reassign)、Leader 不会自己均衡(election)、集群不会自己复制(MM2)。这给了运维完全的控制力 (每一步可审查可限流可回滚),也意味着每个"以为会自动发生"的事都要写进操作手册。和 RocketMQ"流水自动分流"的运维哲学相比,Kafka 更像"管理一个分布式文件系统"------工具链(reassign/MM2/Cruise Control)用熟了,控制力就是生产力。


📌 配套阅读:

上一篇:《06-13-A-Kafka客户端与协议深入详解.md》

下一篇:《06-15-A-Kafka生态集成与流处理详解.md》

如果这篇文章对你有帮助,欢迎点赞、收藏、关注!

相关推荐
IT研究所3 小时前
AI-ITR平台如何减少客户问题反复升级?
大数据·运维·人工智能·低代码·自然语言处理·安全架构·企微
AIgorithmGEEK3 小时前
[Linux]从手写报头到内核套路:序列化、反序列化与自定义协议全链路
linux·运维·服务器·网络·序列化·反序列化
Nil2083 小时前
leetcode 139单词拆分
linux·运维·服务器
Starry-sky(jing)3 小时前
BUG: unable to handle kernel paging request 完整排查:dmesg 四要素与三路定罪
linux·运维·服务器·内核·排障
mounter6253 小时前
从硬件互连到操作系统变革:CXL 技术演进与 Linux 内核工程挑战
linux·运维·服务器
zhengqweasd3 小时前
机房托管服务器怎么选硬盘,机械盘和 SSD 托管场景差异
运维·服务器·github
yumgpkpm4 小时前
Acceldata ODP(Open Data Platform)3.3.6.4(RHEL9)保姆级完整安装手册
大数据·人工智能·hive·hadoop·kafka·hbase·cloudera
心易行者5 小时前
Agent应用+API端点商业化进阶实战:从单体智能体到可付费调用的API全流程
运维·服务器·人工智能·python·apache