kafka broker迁移

发布时间:2026/10/21 14:00:33

kafka broker迁移 此脚本可实现旧 Broker 15 → 新 Broker 69 的健康分区批量迁移真正支持中断恢复可以按 10/20 个 Partition 一批执行直到旧 Broker 的ReplicaCount全部降到 0脚本可实现禁止在已有 reassignment 时提交新批次cd /mnt/allin_data/allin/middleware/software/kafka_2.13-2.7.2 cat kafka_migrate_healthy_partitions.sh SCRIPT #!/bin/bash set -uo pipefail # # Kafka Healthy Partition Migration # # Old brokers : 1,2,3,4,5 # New brokers : 6,7,8,9 # Target RF : 3 # # 每个 Partition 直接 # # old replicas # ↓ # 6,7,8 / 7,8,9 / 8,9,6 / 9,6,7 # # 前提 # URP 0 # Unavailable 0 # # VERSION1.0.0 KAFKA_HOME$(cd $(dirname $0) pwd) TOPICS${KAFKA_HOME}/bin/kafka-topics.sh REASSIGN${KAFKA_HOME}/bin/kafka-reassign-partitions.sh ZKSHELL${KAFKA_HOME}/bin/zookeeper-shell.sh BOOTSTRAP10.40.0.143:9092 ZKcementindustrynode16:2181 BATCH_SIZE20 MAX_BATCHES1 WAIT_INTERVAL10 WAIT_TIMEOUT7200 STATE_DIR/tmp/kafka_healthy_migrate_20260820 EXECUTE0 RESUME0 RUN_ALL0 log() { echo [$(date %F %T)] $* } die() { log ERROR: $* exit 1 } usage() { cat EOF Usage: $0 [OPTIONS] Options: --batch-size N 每批 Partition 数 default: 20 --max-batches N 单次最多执行多少批 default: 1 --execute 正式执行 默认仅生成计划 --resume 继续已有 checkpoint --all 一直处理到完成 --state-dir DIR checkpoint目录 --wait-timeout SEC 单批最长等待时间 default: 7200 Examples: # dry-run $0 --batch-size 10 # 第一批10个 $0 --batch-size 10 --execute # 下一批20个 $0 --batch-size 20 --execute --resume EOF } while [[ $# -gt 0 ]]; do case $1 in --batch-size) BATCH_SIZE$2 shift 2 ;; --max-batches) MAX_BATCHES$2 shift 2 ;; --execute) EXECUTE1 shift ;; --resume) RESUME1 shift ;; --all) RUN_ALL1 shift ;; --state-dir) STATE_DIR$2 shift 2 ;; --wait-timeout) WAIT_TIMEOUT$2 shift 2 ;; -h|--help) usage exit 0 ;; *) die Unknown option $1 ;; esac done mkdir -p $STATE_DIR PLAN${STATE_DIR}/plan.tsv COMPLETED${STATE_DIR}/completed.tsv HISTORY${STATE_DIR}/history.log SNAPSHOT${STATE_DIR}/cluster.txt touch $COMPLETED $HISTORY # # helpers # active_reassignment_count() { $REASSIGN \ --bootstrap-server $BOOTSTRAP \ --list \ 2/dev/null \ | awk /Current partition reassignments/ {next} /No partition reassignments/ {next} /[A-Za-z0-9._-]-[0-9]/ {n} END {print n0} } normalize_csv() { echo $1 | tr , \n | sed /^$/d | sort -n | paste -sd, - } csv_count() { if [[ -z $1 ]]; then echo 0 else echo $1 | awk -F, {print NF} fi } snapshot() { $TOPICS \ --bootstrap-server $BOOTSTRAP \ --describe \ ${SNAPSHOT}.tmp 2${STATE_DIR}/snapshot.err if [[ $? -ne 0 ]]; then cat ${STATE_DIR}/snapshot.err return 1 fi mv ${SNAPSHOT}.tmp $SNAPSHOT } urp_count() { $TOPICS \ --bootstrap-server $BOOTSTRAP \ --describe \ --under-replicated-partitions \ 2/dev/null | awk /Topic:/ {n} END {print n0} } unavailable_count() { $TOPICS \ --bootstrap-server $BOOTSTRAP \ --describe \ --unavailable-partitions \ 2/dev/null | awk /Topic:/ {n} END {print n0} } get_state() { local t$1 local p$2 awk \ -v T$t \ -v P$p { topic part leader replicas isr for(i1;iNF;i) { if($iTopic:) topic$(i1) if($iPartition:) part$(i1) if($iLeader:) leader$(i1) if($iReplicas:) replicas$(i1) if($iIsr:) isr$(i1) } if(topicT partP) { print topic \t part \t leader \t replicas \t isr exit } } $SNAPSHOT } is_completed() { local topic$1 local part$2 awk -F\t \ -v t$topic \ -v p$part $1t $2p {found1} END {exit !found} $COMPLETED } mark_completed() { local topic$1 local part$2 local target$3 if ! is_completed $topic $part; then printf %s\t%s\t%s\t%s\n \ $topic \ $part \ $target \ $(date %F %T) \ $COMPLETED fi } # # Broker health # check_brokers() { local ids ids$( $ZKSHELL $ZK ls /brokers/ids 2/dev/null | grep ^\[ | tail -1 ) log Brokers: $ids for id in 6 7 8 9; do echo $ids | grep -Eq (^|[^0-9])${id}([^0-9]|$) || die New Broker $id not online done } # # 生成迁移计划 # # 仅选择仍然包含旧 Broker 1~5 的 Partition # # 最终目标轮转 # 6,7,8 # 7,8,9 # 8,9,6 # 9,6,7 # generate_plan() { snapshot || die snapshot failed $PLAN local idx0 while IFS$\t read -r topic part leader replicas isr do [[ -z $topic ]] continue local has_old0 IFS, read -ra R $replicas for r in ${R[]}; do if (( r 1 r 5 )); then has_old1 fi done [[ $has_old -eq 0 ]] continue local target case $((idx % 4)) in 0) target6,7,8 ;; 1) target7,8,9 ;; 2) target8,9,6 ;; 3) target9,6,7 ;; esac printf %d\t%s\t%s\t%s\t%s\n \ $idx \ $topic \ $part \ $replicas \ $target \ $PLAN idx$((idx1)) done ( awk { t p l r s for(i1;iNF;i) { if($iTopic:) t$(i1) if($iPartition:) p$(i1) if($iLeader:) l$(i1) if($iReplicas:) r$(i1) if($iIsr:) s$(i1) } if(t!) print t \t p \t l \t r \t s } $SNAPSHOT ) log Migration plan partitions: $(wc -l $PLAN) } ACTIVE$(active_reassignment_count) if [[ $ACTIVE -ne 0 ]]; then log Kafka currently has $ACTIVE active partition reassignments. $REASSIGN \ --bootstrap-server $BOOTSTRAP \ --list die Wait for current reassignment to complete before starting another batch. fi # # 构建下一批 # build_batch() { local outfile$1 $outfile snapshot || die snapshot failed while IFS$\t read -r idx topic part original target do [[ -z $topic ]] continue if is_completed $topic $part; then continue fi local state state$(get_state $topic $part) [[ -z $state ]] die Partition disappeared: $topic-$part local ct cp leader replicas isr IFS$\t read -r \ ct cp leader replicas isr $state local norm_target local norm_rep local norm_isr norm_target$(normalize_csv $target) norm_rep$(normalize_csv $replicas) norm_isr$(normalize_csv $isr) # 已经完全迁完 if [[ $norm_rep $norm_target $norm_isr $norm_target $(csv_count $isr) -eq 3 ]]; then mark_completed $topic $part $target continue fi # 已经执行 reassignment但新副本还在追数据 if [[ $norm_rep $norm_target ]]; then log Resume in-progress: $topic-$part Replicas$replicas ISR$isr else # 正常健康状态才能开始新的 reassignment if [[ $(normalize_csv $replicas) ! $(normalize_csv $isr) ]]; then die Partition not healthy before migration: $topic-$part Replicas$replicas ISR$isr fi log Candidate $topic-$part $replicas - $target fi printf %s\t%s\t%s\n \ $topic \ $part \ $target \ $outfile if [[ $(wc -l $outfile) -ge $BATCH_SIZE ]]; then break fi done $PLAN } # # JSON # generate_json() { local input$1 local output$2 awk -F\t BEGIN { print { print \version\: 1, print \partitions\: [ first1 } { split($3,r,,) if(!first) print , printf {\topic\:\%s\,\partition\:%s,\replicas\:[%s,%s,%s],\log_dirs\:[\any\,\any\,\any\]}, $1,$2,r[1],r[2],r[3] first0 } END { print print ] print } } $input $output } # # 等待本批完成 # wait_ready() { local batch$1 local start start$(date %s) while true; do snapshot || die snapshot failed local pending0 local total0 while IFS$\t read -r topic part target do total$((total1)) local state state$(get_state $topic $part) local ct cp leader replicas isr IFS$\t read -r \ ct cp leader replicas isr $state local nt local nr local ni nt$(normalize_csv $target) nr$(normalize_csv $replicas) ni$(normalize_csv $isr) if [[ $nr $nt $ni $nt $(csv_count $isr) -eq 3 ]]; then log READY $topic-$part Replicas$replicas ISR$isr else log WAIT $topic-$part Replicas$replicas ISR$isr Target$target pending$((pending1)) fi done $batch local unavailable unavailable$(unavailable_count) local urp urp$(urp_count) log Batch status: pending$pending/$total URP$urp Unavailable$unavailable if [[ $unavailable -ne 0 ]]; then die Unavailable partitions detected: $unavailable fi if [[ $pending -eq 0 ]]; then return 0 fi if (( $(date %s) - start WAIT_TIMEOUT )); then die Timeout waiting for batch fi sleep $WAIT_INTERVAL done } # # execute one batch # execute_batch() { local num$1 local batch$2 local json${STATE_DIR}/batch_${num}.json generate_json $batch $json log log BATCH $num log cat $json if [[ $EXECUTE -eq 0 ]]; then log DRY-RUN - not executing return 2 fi # 先判断哪些已经处于目标 replicas # resume情况下避免重复execute snapshot || die snapshot failed local need_execute0 while IFS$\t read -r topic part target do state$(get_state $topic $part) IFS$\t read -r \ ct cp leader replicas isr $state if [[ $(normalize_csv $replicas) ! $(normalize_csv $target) ]]; then need_execute1 fi done $batch if [[ $need_execute -eq 1 ]]; then $REASSIGN \ --bootstrap-server $BOOTSTRAP \ --reassignment-json-file $json \ --execute \ 21 | tee -a $HISTORY rc${PIPESTATUS[0]} [[ $rc -eq 0 ]] || die Reassignment execute failed else log Batch already assigned; continuing wait fi wait_ready $batch # verify 清 throttle $REASSIGN \ --bootstrap-server $BOOTSTRAP \ --reassignment-json-file $json \ --verify \ 21 | tee -a $HISTORY || true while IFS$\t read -r topic part target do mark_completed $topic $part $target done $batch log BATCH $num SUCCESS } # # MAIN # log Kafka Healthy Migration v$VERSION log Bootstrap : $BOOTSTRAP log BatchSize : $BATCH_SIZE log StateDir : $STATE_DIR log Execute : $EXECUTE log Resume : $RESUME check_brokers U$(unavailable_count) R$(urp_count) # # 禁止在已有 reassignment 时提交新批次 # ACTIVE_REASSIGN$( $REASSIGN \ --bootstrap-server $BOOTSTRAP \ --list \ 2/dev/null ) if echo $ACTIVE_REASSIGN \ | grep -qE ^[[:space:]]*[A-Za-z0-9._-]-[0-9][[:space:]]; then log Existing Kafka partition reassignment detected: echo $ACTIVE_REASSIGN die Existing reassignment is still running. Wait until it finishes, then --resume. fi log Initial URP$R Unavailable$U [[ $U -eq 0 ]] || die Unavailable ! 0 [[ $R -eq 0 ]] || die URP ! 0 before migration if [[ $RESUME -eq 1 -s $PLAN ]]; then log Using existing plan else if [[ $RESUME -eq 0 -s $PLAN ]]; then die State exists. Use --resume or another --state-dir fi generate_plan fi batch_num1 executed0 while true; do BATCH${STATE_DIR}/current_batch.tsv build_batch $BATCH count$(wc -l $BATCH) if [[ $count -eq 0 ]]; then log No old-broker partitions remaining in plan. break fi log Next batch partitions$count column -t -s $\t $BATCH 2/dev/null || cat $BATCH execute_batch $batch_num $BATCH rc$? if [[ $rc -eq 2 ]]; then exit 0 fi executed$((executed1)) batch_num$((batch_num1)) if [[ $RUN_ALL -ne 1 $executed -ge $MAX_BATCHES ]]; then break fi done snapshot remaining$( awk { replicas for(i1;iNF;i) if($iReplicas:) replicas$(i1) nsplit(replicas,a,,) for(i1;in;i) if(a[i]1 a[i]5) { count break } } END { print count0 } $SNAPSHOT ) log log SUMMARY log log Completed checkpoints : $(wc -l $COMPLETED) log Remaining old partitions: $remaining log URP : $(urp_count) log Unavailable : $(unavailable_count) SCRIPT chmod x kafka_migrate_healthy_partitions.sh bash -n kafka_migrate_healthy_partitions.shbash -n无输出才继续第一批仍建议先 10 个先 dry-run./kafka_migrate_healthy_partitions.sh \ --batch-size 10 \ --state-dir /tmp/kafka_healthy_migrate_20260820你应该看到Migration plan partitions: 2470Next batch partitions10topicA 0 6,7,8topicB 1 7,8,9topicC 2 8,9,6...确认没有问题以后正式./kafka_migrate_healthy_partitions.sh \ --batch-size 10 \ --state-dir /tmp/kafka_healthy_migrate_20260820 \ --execute \ --resume第一批完成以后bin/kafka-topics.sh \ --bootstrap-server 10.40.0.143:9092 \ --describe \ --under-replicated-partitions | wc -lbin/kafka-topics.sh \ --bootstrap-server 10.40.0.143:9092 \ --describe \ --unavailable-partitions | wc -l最终都应恢复为URP0Unavailable0然后下一批可以提高到 20./kafka_migrate_healthy_partitions.sh \ --batch-size 20 \ --state-dir /tmp/kafka_healthy_migrate_20260820 \ --execute \ --resume建议暂时不要用--all。你现在底层 SmartPQI 故障还没有物理处理掉2470 个 Partition 一次连续复制风险过高。建议人工一批一批跑先10 → 20 → 20...。等 active reassignment0 后再重新启动脚本
延伸阅读

更多相关文章

2026/10/20 17:46:32

从L1-027出租题解看暴力算法在C++中的实践与优化

1. 从一道题看“暴力”的智慧:L1-027 出租的解题思路 最近在带新人刷题,又看到了PTA(程序设计类实验辅助教学平台)上这道经典的L1-027“出租”。题目本身不难,但很有意思,它像一面镜子,能清晰地…

2026/10/16 17:57:50

本科人工智能专业课程与考级(证)清单

本文基于本人所在院校首届人工智能专业的真实培养方案,把全部专业课程按内容分成八大类并逐门详细介绍。供同专业或想报考人工智能专业的同学参考。 一、课程分类培养方案中的课程按内容可分成八大类。光看课名容易一头雾水,下面我按自己的理解逐类聊聊&…

2026/10/19 22:48:40

睡眠耳机选购指南:从佩戴舒适度到降噪效果,实测避坑全解析

1. 先搞清楚“睡眠耳机”到底解决什么问题,以及它和普通耳机的区别如果你经常因为环境噪音、伴侣打鼾、或者单纯想听点助眠声音而睡不着,然后去搜“睡眠耳机”,大概率会看到一堆长得像耳塞、宣传能“主动降噪”、“无感佩戴”、“助眠音乐”的…

2026/10/21 13:57:08

C++ set的使用方法详解

前言 std::set 是 C 标准库中的有序关联容器:它保存一组互不相同的元素,并按比较器维持顺序。需要"去重 有序 快速查找"时,它往往是最直接的选择。元素一旦进入容器,位置就由比较器决定,因此标准不允许通过…

2026/10/21 13:57:08

Python本地教务系统:Tkinter+SQLite三端权限闭环

简介:本资源是一个基于Python开发的轻量级学校教务系统实战项目,面向Python初学者及Web开发入门学习者,聚焦教育管理场景下的学生信息、课程安排、成绩录入与查询等核心教务流程自动化。压缩包共9个文件,含7个SQL建表与初始化脚本…

2026/10/21 13:57:08

Servlet+JSP集成ECharts实现成绩统计可视化

简介:这是一套基于ServletJSPMySQL开发的JavaWeb学生成绩管理系统实战项目,面向Java初学者与Web开发入门学习者,聚焦教学管理场景下的成绩录入、查询、统计与可视化需求。资源包共344个文件,包含86个Java源码(如ScoreD…

2026/10/21 13:57:08

Servlet+JSP+MySQL学生成绩系统:增删改查与ECharts图表实战

简介:这是一套基于ServletJSPMySQL实现的JavaWeb学生成绩管理系统升级版,面向Java初学者与Web开发入门学习者,聚焦教学管理场景下的成绩录入、查询、统计与可视化需求。资源包共344个文件,包含86个Java源码(如ScoreDao…

2026/10/21 13:57:08

个人技能管理体系搭建实战:从技能树到复盘

把“skills”当成一个项目标题来拆,其实是件很有意思的事。它不是一个具体功能,也不是一个系统名称,它指的是——你身上那堆能力,到底是怎么被组织起来的。我见过太多人,简历上写“掌握十几种软件”,真上手…

2026/10/21 13:52:02

VMware安装CentOS 7最小化系统完整指南

1. 为什么现在还要亲手装一遍 CentOS 7 虚拟机?这根本不是“过时操作”你点开这个标题,大概率正面临三种真实场景:刚接触 Linux 的学生在实验室里对着 VMware Workstation 发呆;运维新人被要求在测试环境复现一个老系统的运行条件…

2026/10/21 4:53:08

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/21 0:00:35

交通流仿真实战:IDM跟驰与MOBIL换道模型参数调优与避坑指南

简介:这份资源是面向交通工程学习者与Python开发者的微观交通流仿真项目,核心实现智能驾驶模型(IDM)下的车辆跟驰与换道行为,可用于理解速度、密度与流量之间的动态关系,适合具备Python基础、希望深入交通模…

2026/10/21 0:00:35

揭穿智能体表面顺从:用追踪代码重建任务执行确定性

1. 表面顺从不是智能体的“礼貌”,而是任务执行链路上的隐性断点最近在调试一个跨平台长周期任务调度系统时,我反复遇到一种令人困惑的现象:智能体在用户指令发出后,几乎秒级响应“已收到”“正在处理”“请稍候”,UI上…

2026/10/21 0:00:35

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑