HDFS 磁盘均衡实战:从 Balancer 到 Disk Balancer
区分节点间 Balancer 与节点内 Disk Balancer 的场景边界,给出阈值设置、执行节奏与故障节点下线恢复操作
排查 HDFS 磁盘使用不均,第一步不是调参数,而是判断不均发生在哪个层面:是集群里不同 DataNode 之间的负载差得远,还是同一个 DataNode 的多块磁盘之间差得远。这两个问题的成因不同、工具不同、处理节奏也不同。混为一谈,是绝大多数"均衡跑了很多天还是没有效果"案例的起点。
判断方法很简单。看节点间不均,用 hdfs dfsadmin -report 观察各 DataNode 的 DFS Used 百分比,若彼此差距超过 20%,属于节点间偏斜;看节点内不均,登录单台机器观察各数据目录的占用,若同一节点上某块盘接近写满、另一块盘还很空,而 NameNode 日志里已经出现"Disk out of space"告警但整机剩余空间充足,属于节点内多盘偏斜。前者是分布问题,后者是卷分配问题,对应工具分别是 hdfs balancer 与 hdfs diskbalancer。
节点间不均的成因,根源在副本分布与写入模式的叠加。HDFS 默认机架感知写策略把第一个副本落在写入客户端所在节点,第二个副本在同机架另一节点,第三个副本跨机架。这意味着数据总是"就近优先"落盘:热点任务长期在固定节点运行,这些节点的水位会持续高于集群平均值;新节点加入时磁盘是空的,需要长时间追赶;下线过节点后,其副本由 NameNode 重新复制到存活节点,复制目标的选择也可能造成新一轮偏斜;还有一类常见情况是集群分批采购、磁盘容量不一致,同一套均衡阈值对不同容量的节点意义完全不同。把成因拆开,才能决定均衡的优先级与节奏。
治理节点间不均,用 hdfs balancer。它工作在节点粒度,目标是把每个 DataNode 的使用率拉回与集群平均值的差在 threshold 以内,默认阈值 10%。参数上要一起看三样:-threshold 控制收敛目标,调得太小(比如 2%)会让均衡长时间跑不完还频繁移动数据;-Ddfs.datanode.balance.bandwidthPerSec 控制均衡可占用的带宽,默认只有 1MB/s,对大集群几乎等于不工作,实践中先用 hdfs dfsadmin -setBalancerBandwidth 动态调大(例如 50-100MB/s)再启动均衡;-Ddfs.balancer.movedWinWidth 与 -Ddfs.balancer.moverThreads 决定每个迭代窗口内移动的块数与线程数,直接影响收敛速度与 NameNode 压力之间的平衡。
执行节奏上,节点间均衡应当作为例行维护而不是一次性动作。建议每周或每两周在业务低谷(例如凌晨)运行一次,用 nohup 挂后台并记录日志,每次观察 moved 字节数:如果连续几轮 moved 接近零,说明集群已到当前阈值下的平衡点,可以停止而不是空转。注意与业务高峰错开,均衡带宽与写入流量叠加会抬高延迟;对磁盘容量不一致的集群,应按节点容量分组观察使用率,而不是只盯集群平均值。
节点内多盘不均则是另一个故事。HDFS 在 DataNode 内分配块时默认偏向剩余空间最多的卷,但大量小文件、短写入,或某块盘被标记为卷故障后,剩余卷会承接全部写入;SSD 与 HDD 混布、磁盘容量不一致时,偏斜会加速。治理工具是 Disk Balancer,这是 HDFS-1312 引入、自 Hadoop 2.10 与 3.0 起可用的官方能力(官方文档)。它的工作方式是计划、执行、查询三步:先 hdfs diskbalancer -plan datanode 生成节点均衡计划,默认写入 /system/diskbalancer 目录,计划列出每块盘的搬移方案;确认后用 -execute 执行;期间用 -query datanode 查询进度与剩余字节数。它只做卷内与卷间的数据搬移,不改变节点间副本分布,因此与 balancer 是互补关系:节点间不均用 Balancer,单节点盘间不均用 Disk Balancer。执行前同样要先调大带宽,否则几十 TB 的搬移要跑数周。
故障 DataNode 的下线与恢复,是运维里另一个高频动作,处理不当会直接放大磁盘不均。节点故障或需要替换硬件时,不要直接 kill 进程或拔盘,而是走 decommission:通过 dfsadmin 的 decommission 命令(或 -refreshNodes 配合 exclude 文件)把节点标记为下线中,NameNode 会把该节点上的副本逐步复制到其他节点,期间业务不中断;用 dfsadmin -report 观察节点状态从 Decommission in progress 变为 Decommissioned 后,再安全停机和移除。恢复时从 exclude 文件移除该节点并执行 -refreshNodes,或使用 recommission 命令让节点重新加入。两个要点:decommission 期间的数据复制同样占用集群带宽,要与均衡任务错开;若节点上存在大量唯一副本(副本数为 1 的冷数据),decommission 会卡在 under-replicated 状态,需要先评估数据冗余度并补副本。
阈值与失败模式可以给一组实践建议:节点间水位差控制在 10% 以内算健康,10%-20% 安排例行均衡,超过 20% 立即干预;Disk Balancer 在发现单盘偏斜超过 10% 或每季度执行一次。常见失败模式:带宽设得太小导致均衡永远跑不完,先调带宽再看阈值;均衡与业务高峰重叠导致写入延迟升高,用定时调度规避;Disk Balancer 计划生成失败,常见于磁盘剩余空间不足或卷目录不可写,先清理空间再重新 plan;decommission 卡住,优先排查副本不足与机架感知策略,必要时临时调整下线节点的副本优先级。
这类运维最好被持续观测,而不是靠人工翻 report。像 EasyMR 这类基于开源 Hadoop 自研增强的国产化大数据底座平台,集成 Hive、Spark、Flink、Kyuubi 等引擎与 YARN、HDFS,通过 EasyManager 提供集群部署、自动化运维、深度巡检与实时监控告警,可以在均衡与下线期间自动盯住 DataNode 磁盘水位与 NameNode 状态,把"事后救火"变成"事前发现"。无论是否使用平台,把阈值、节奏与失败模式固化成运维清单,比任何一次性调优都更有长期价值。
给一个具体示例帮助校准阈值。假设集群平均使用率 60%,某节点 75%,节点容量 20TB,则该节点相对平均值多出了约 3TB 数据(20TB 的 15%),Balancer 需要移动约 1.5TB 才能把它拉回阈值以内(阈值 10% 意味着只要与平均值差小于 10% 即可停)。按 100MB/s 带宽估算,移动 1.5TB 需要约 4 小时,这就是为什么"深夜跑一次均衡"往往不够,需要按数据量倒推运行时长。另一个实用技巧是分批次收敛:先用 -threshold 15 跑一轮粗均衡,再用 -threshold 5 精调,比一步到位更快,也避免均衡器在临界块上反复搬移。多 namespace 场景下还可以用 -policy 选择均衡策略(默认 datanode 策略按节点聚合,blockpool 策略细到每个 blockpool),需要与集群结构配合使用。
下一步建议:先在测试集群完整复现一次"诊断、均衡、下线恢复"流程,把本文的阈值与命令固化成巡检脚本,再在生产集群低峰期执行第一次节点间均衡,记录移动字节数与耗时作为基线,之后每周对比基线判断是否需要调整带宽与频率。


