目录

概述

HDFS均衡器(Balancer)是Hadoop分布式文件系统中的一个重要工具,用于重新分布数据块,确保集群中所有DataNode的存储使用率保持相对均衡。当集群中添加新节点或删除节点后,数据分布可能会变得不均匀,这时就需要使用均衡器来重新分布数据。

什么时候需要HDFS均衡

1. 集群扩容后

  • 新增DataNode节点:新节点加入集群后,存储使用率为0%,而原有节点可能已经接近满载
  • 添加存储设备:为现有DataNode添加新的磁盘后

2. 集群缩容后

  • 移除DataNode节点:节点下线前需要将其数据迁移到其他节点
  • 磁盘故障:某个磁盘故障后,需要重新分布数据

3. 数据倾斜

  • 节点间使用率差异过大:标准差超过10-15%
  • 热点数据:某些节点存储了过多的热点数据
  • 写入模式不均:应用写入模式导致的数据分布不均

4. 性能优化

  • 负载均衡:提高集群整体I/O性能
  • 故障恢复:确保数据副本分布合理

判断标准

1
2
3
4
# 计算节点使用率标准差
# 标准差 > 10%:建议进行均衡
# 标准差 > 20%:强烈建议立即均衡
# 标准差 < 5%:认为已均衡

HDFS均衡原理

1. 均衡策略

  • DataNode策略:基于整个DataNode的使用率进行均衡
  • BlockPool策略:基于命名空间的使用率进行均衡(适用于Federation)

2. 均衡算法

  1. 识别源节点:使用率高于平均值的节点
  2. 识别目标节点:使用率低于平均值的节点
  3. 选择数据块:从源节点选择合适的数据块
  4. 数据迁移:通过三阶段复制进行数据迁移
  5. 验证完整性:确保数据迁移成功

3. 数据迁移过程

1
源节点 → 中间节点 → 目标节点
  • 避免直接复制,减少网络压力
  • 通过中间节点进行数据转发
  • 确保数据完整性和一致性

均衡参数详解

1. 基本参数

-threshold <threshold>

  • 用途:设置均衡阈值,单位为百分比
  • 默认值:10%
  • 说明:只有当节点使用率差异超过此阈值时才开始均衡
  • 推荐值
  • 生产环境:5-10%
  • 测试环境:10-15%
  • 紧急情况:20%
1
2
3
# 示例
hdfs balancer -threshold 5    # 5%阈值,更严格的均衡
hdfs balancer -threshold 15   # 15%阈值,更宽松的均衡

-policy <policy>

  • 用途:指定均衡策略
  • 可选值
  • datanode:基于DataNode使用率(默认)
  • blockpool:基于BlockPool使用率
  • 推荐:一般使用datanode策略
1
2
3
# 示例
hdfs balancer -policy datanode    # DataNode策略
hdfs balancer -policy blockpool   # BlockPool策略

2. 节点选择参数

-exclude [-f <hosts-file> | <comma-separated list of hosts>]

  • 用途:排除指定的DataNode节点
  • 使用场景
  • 节点维护期间
  • 性能较差的节点
  • 网络不稳定的节点
1
2
3
4
5
6
7
8
# 排除单个节点
hdfs balancer -exclude 192.168.1.100

# 排除多个节点
hdfs balancer -exclude 192.168.1.100,192.168.1.101

# 从文件读取排除列表
hdfs balancer -exclude -f /path/to/exclude_hosts.txt

-include [-f <hosts-file> | <comma-separated list of hosts>]

  • 用途:只对指定的DataNode节点进行均衡
  • 使用场景
  • 只均衡特定节点
  • 测试环境
  • 部分节点维护
1
2
# 只均衡指定节点
hdfs balancer -include 192.168.1.100,192.168.1.101

-source [-f <hosts-file> | <comma-separated list of hosts>]

  • 用途:指定源节点(数据来源)
  • 使用场景
  • 特定节点需要减少负载
  • 节点即将下线
1
2
# 指定源节点
hdfs balancer -source 192.168.1.100,192.168.1.101

3. 性能控制参数

-idleiterations <idleiterations>

  • 用途:设置连续空闲迭代次数
  • 默认值:5
  • 说明:连续N次迭代没有数据移动时退出
  • 推荐值
  • 生产环境:3-5
  • 测试环境:1-2
1
2
# 示例
hdfs balancer -idleiterations 3  # 连续3次无移动则退出

-runDuringUpgrade

  • 用途:在HDFS升级期间运行均衡器
  • 默认值:false
  • 说明:通常不建议在升级期间运行

4. 高级参数

-blockpools <comma-separated list of blockpool ids>

  • 用途:指定要均衡的BlockPool ID
  • 适用场景:Federation环境
1
2
# 示例
hdfs balancer -blockpools BP-REPLACE_WITH_NEW_PASSWORD789-192.168.1.100-REPLACE_WITH_NEW_PASSWORD7890123

操作步骤

1. 环境检查

检查集群状态

1
2
3
4
5
6
7
8
# 检查HDFS状态
hdfs dfsadmin -report

# 检查NameNode状态
hdfs haadmin -getServiceState nn1

# 检查DataNode状态
hdfs dfsadmin -printTopology

检查磁盘空间

1
2
3
4
5
# 检查各节点磁盘使用情况
for node in $(hdfs dfsadmin -printTopology | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+'); do
    echo "=== $node ==="
    ssh $node "df -h"
done

检查网络状况

1
2
3
4
5
# 检查节点间网络延迟
hdfs dfsadmin -printTopology | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+' | while read node; do
    echo "Testing $node..."
    ping -c 3 $node
done

2. 均衡前准备

备份重要配置

1
2
3
4
5
# 备份HDFS配置
cp -r $HADOOP_CONF_DIR /backup/hdfs_conf_$(date +%Y%m%d)

# 记录当前状态
hdfs dfsadmin -report > /backup/hdfs_report_$(date +%Y%m%d_%H%M%S).txt

设置均衡参数

1
2
3
4
5
6
# 设置均衡带宽(可选)
# 在hdfs-site.xml中添加:
# <property>
#   <name>dfs.datanode.balance.bandwidthPerSec</name>
#   <value>10485760</value>  <!-- 10MB/s -->
# </property>

3. 执行均衡

基本均衡命令

1
2
3
4
5
6
7
8
# 标准均衡命令
nohup hdfs balancer -threshold 10 -policy datanode > /tmp/hdfs_balancer.log 2>&1 &

# 获取进程ID
BALANCER_PID=$!

# 记录PID
echo $BALANCER_PID > /tmp/hdfs_balancer.pid

高级均衡命令

1
2
3
4
5
6
7
8
# 排除特定节点的均衡
nohup hdfs balancer -threshold 5 -policy datanode \
    -exclude 192.168.1.100,192.168.1.101 \
    -idleiterations 3 > /tmp/hdfs_balancer.log 2>&1 &

# 只对特定节点进行均衡
nohup hdfs balancer -threshold 10 -policy datanode \
    -include 192.168.1.102,192.168.1.103 > /tmp/hdfs_balancer.log 2>&1 &

4. 监控均衡进度

实时监控脚本

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3
# monitor_hdfs_balancer.py
import subprocess
import time
import re
from datetime import datetime

def get_hdfs_report():
    try:
        result = subprocess.run(['hdfs', 'dfsadmin', '-report'],
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                              universal_newlines=True, check=True)
        return result.stdout
    except subprocess.CalledProcessError as e:
        print("获取HDFS报告失败: {}".format(e))
        return None

def parse_datanode_info(report):
    datanodes = []
    lines = report.split('\n')

    current_node = {}
    in_datanode_section = False

    for line in lines:
        line = line.strip()

        if line.startswith('Name:'):
            if current_node:
                datanodes.append(current_node)
            current_node = {'name': line.split(':', 1)[1].strip()}
            in_datanode_section = True

        elif in_datanode_section and line.startswith('DFS Used%:'):
            current_node['used_percent'] = float(line.split(':')[1].strip().replace('%', ''))

        elif in_datanode_section and line.startswith('DFS Remaining%:'):
            current_node['remaining_percent'] = float(line.split(':')[1].strip().replace('%', ''))

    if current_node:
        datanodes.append(current_node)

    return datanodes

def calculate_balance_metrics(datanodes):
    if not datanodes:
        return None

    used_percents = [node.get('used_percent', 0) for node in datanodes]
    avg_used_percent = sum(used_percents) / len(used_percents)

    # 计算标准差
    variance = sum((x - avg_used_percent) ** 2 for x in used_percents) / len(used_percents)
    std_dev = variance ** 0.5

    # 找出最高和最低使用率节点
    max_used_node = max(datanodes, key=lambda x: x.get('used_percent', 0))
    min_used_node = min(datanodes, key=lambda x: x.get('used_percent', 0))

    return {
        'avg_used_percent': avg_used_percent,
        'std_dev': std_dev,
        'max_used_node': max_used_node,
        'min_used_node': min_used_node,
        'datanodes': datanodes
    }

def monitor_balancer():
    print("HDFS均衡监控开始...")
    print("=" * 80)

    start_time = datetime.now()

    try:
        while True:
            current_time = datetime.now()
            elapsed = current_time - start_time

            report = get_hdfs_report()
            if not report:
                print("[{}] 无法获取HDFS报告".format(current_time.strftime('%H:%M:%S')))
                time.sleep(30)
                continue

            datanodes = parse_datanode_info(report)
            if not datanodes:
                print("[{}] 无法解析datanode信息".format(current_time.strftime('%H:%M:%S')))
                time.sleep(30)
                continue

            metrics = calculate_balance_metrics(datanodes)
            if not metrics:
                continue

            # 显示当前状态
            print("\n[{}] 运行时间: {}".format(current_time.strftime('%H:%M:%S'), elapsed))
            print("平均使用率: {:.2f}%".format(metrics['avg_used_percent']))
            print("均衡度(标准差): {:.2f}%".format(metrics['std_dev']))
            print("最高使用率节点: {} ({:.2f}%)".format(
                metrics['max_used_node'].get('name', 'N/A'),
                metrics['max_used_node'].get('used_percent', 0)))
            print("最低使用率节点: {} ({:.2f}%)".format(
                metrics['min_used_node'].get('name', 'N/A'),
                metrics['min_used_node'].get('used_percent', 0)))

            print("\n各节点使用率:")
            for node in sorted(metrics['datanodes'], key=lambda x: x.get('used_percent', 0), reverse=True):
                name = node.get('name', 'N/A')
                used_pct = node.get('used_percent', 0)
                remaining_pct = node.get('remaining_percent', 0)
                print("  {}: {:.2f}% (剩余: {:.2f}%)".format(name, used_pct, remaining_pct))

            # 检查是否达到均衡
            if metrics['std_dev'] < 5.0:
                print("\n🎉 均衡完成! 标准差: {:.2f}%".format(metrics['std_dev']))
                break

            print("=" * 80)
            time.sleep(60)

    except KeyboardInterrupt:
        print("\n\n监控已停止")
    except Exception as e:
        print("\n监控出错: {}".format(e))

if __name__ == "__main__":
    monitor_balancer()

手动检查命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 检查均衡进程状态
ps aux | grep balancer

# 查看均衡日志
tail -f /tmp/hdfs_balancer.log

# 检查集群状态
hdfs dfsadmin -report | grep -A 20 "Live datanodes"

# 计算当前均衡度
python3 -c "
import subprocess
import re

result = subprocess.run(['hdfs', 'dfsadmin', '-report'],
                       stdout=subprocess.PIPE, universal_newlines=True)
report = result.stdout

used_percents = []
for line in report.split('\n'):
    if 'DFS Used%:' in line:
        percent = float(re.search(r'(\d+\.?\d*)%', line).group(1))
        used_percents.append(percent)

if used_percents:
    avg = sum(used_percents) / len(used_percents)
    variance = sum((x - avg) ** 2 for x in used_percents) / len(used_percents)
    std_dev = variance ** 0.5
    print(f'平均使用率: {avg:.2f}%')
    print(f'标准差: {std_dev:.2f}%')
    print(f'最高使用率: {max(used_percents):.2f}%')
    print(f'最低使用率: {min(used_percents):.2f}%')
"

监控和管理

1. 均衡状态监控

实时监控

1
2
3
4
5
# 启动监控脚本
python3 /tmp/monitor_hdfs_balancer.py

# 后台运行监控
nohup python3 /tmp/monitor_hdfs_balancer.py > /tmp/balancer_monitor.log 2>&1 &

定期检查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 创建定期检查脚本
cat > /tmp/check_balance.sh << 'EOF'
#!/bin/bash
LOG_FILE="/tmp/balance_check.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$DATE] 开始检查HDFS均衡状态" >> $LOG_FILE

# 检查均衡进程
if pgrep -f "hdfs.*balancer" > /dev/null; then
    echo "[$DATE] 均衡进程正在运行" >> $LOG_FILE
else
    echo "[$DATE] 警告: 均衡进程未运行" >> $LOG_FILE
fi

# 检查集群状态
hdfs dfsadmin -report | grep -A 20 "Live datanodes" >> $LOG_FILE

echo "[$DATE] 检查完成" >> $LOG_FILE
echo "----------------------------------------" >> $LOG_FILE
EOF

chmod +x /tmp/check_balance.sh

# 添加到crontab,每10分钟检查一次
echo "*/10 * * * * /tmp/check_balance.sh" | crontab -

2. 均衡进程管理

启动均衡

1
2
3
4
5
6
7
# 基本启动
nohup hdfs balancer -threshold 10 > /tmp/balancer.log 2>&1 &

# 高级启动
nohup hdfs balancer -threshold 5 -policy datanode \
    -exclude 192.168.1.100 -idleiterations 3 \
    > /tmp/balancer.log 2>&1 &

停止均衡

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查找均衡进程
BALANCER_PID=$(pgrep -f "hdfs.*balancer")

# 停止均衡进程
if [ ! -z "$BALANCER_PID" ]; then
    kill $BALANCER_PID
    echo "均衡进程 $BALANCER_PID 已停止"
else
    echo "未找到运行中的均衡进程"
fi

重启均衡

1
2
3
4
5
6
7
8
# 停止现有均衡
pkill -f "hdfs.*balancer"

# 等待进程完全停止
sleep 5

# 重新启动均衡
nohup hdfs balancer -threshold 10 > /tmp/balancer.log 2>&1 &

3. 日志分析

均衡日志分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 统计移动的数据块数量
grep "Successfully moved" /tmp/hdfs_balancer.log | wc -l

# 统计移动的数据量
grep "Successfully moved" /tmp/hdfs_balancer.log | \
    awk '{sum += $NF} END {print "总移动数据量: " sum/1024/1024/1024 " GB"}'

# 分析移动速度
grep "Successfully moved" /tmp/hdfs_balancer.log | \
    awk '{print $1, $2, $NF}' | \
    tail -100 | \
    awk 'BEGIN{prev_time=""} {
        if(prev_time != "") {
            split($1" "$2, time_arr, ":")
            current_sec = time_arr[1]*3600 + time_arr[2]*60 + time_arr[3]
            split(prev_time, prev_arr, ":")
            prev_sec = prev_arr[1]*3600 + prev_arr[2]*60 + prev_arr[3]
            if(current_sec > prev_sec) {
                speed = $3 / (current_sec - prev_sec)
                print "移动速度: " speed/1024/1024 " MB/s"
            }
        }
        prev_time = $1" "$2
    }'

故障排除

1. 常见问题

均衡进程无法启动

症状:执行均衡命令后立即退出 可能原因

  • HDFS服务未正常运行
  • 权限不足
  • 配置错误

解决方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 检查HDFS服务状态
hdfs dfsadmin -report

# 检查权限
whoami
groups

# 检查配置
hdfs getconf -confKey dfs.namenode.rpc-address

# 查看错误日志
tail -f $HADOOP_LOG_DIR/hadoop-*-balancer-*.log

均衡速度过慢

症状:数据移动速度很慢,均衡时间过长 可能原因

  • 网络带宽限制
  • 磁盘I/O性能差
  • 均衡带宽设置过低

解决方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 检查网络带宽
iperf3 -s &  # 在源节点启动服务器
iperf3 -c <source_node> -t 60  # 在目标节点测试

# 检查磁盘I/O
iostat -x 1 5

# 调整均衡带宽
# 在hdfs-site.xml中设置:
# <property>
#   <name>dfs.datanode.balance.bandwidthPerSec</name>
#   <value>52428800</value>  <!-- 50MB/s -->
# </property>

# 重启DataNode服务
sudo systemctl restart hadoop-datanode

均衡进程异常退出

症状:均衡进程运行一段时间后自动退出 可能原因

  • 内存不足
  • 网络中断
  • 磁盘空间不足

解决方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 检查系统资源
free -h
df -h
dmesg | tail -50

# 检查均衡日志
tail -100 /tmp/hdfs_balancer.log

# 检查HDFS日志
tail -100 $HADOOP_LOG_DIR/hadoop-*-balancer-*.log

# 重新启动均衡
nohup hdfs balancer -threshold 10 > /tmp/balancer_retry.log 2>&1 &

2. 性能问题

网络瓶颈

诊断

1
2
3
4
5
6
7
8
# 检查网络使用情况
iftop -i eth0

# 检查网络延迟
ping -c 10 <target_node>

# 检查网络丢包
mtr -r -c 10 <target_node>

优化

1
2
3
4
# 调整网络参数
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
sysctl -p

磁盘I/O瓶颈

诊断

1
2
3
4
5
6
7
8
# 检查磁盘使用情况
iostat -x 1 10

# 检查磁盘队列
iostat -x 1 10 | grep -E "(Device|sd)"

# 检查磁盘错误
dmesg | grep -i error

优化

1
2
3
4
5
# 调整I/O调度器
echo noop > /sys/block/sda/queue/scheduler

# 调整I/O参数
echo 1024 > /sys/block/sda/queue/nr_requests

3. 数据完整性检查

均衡后验证

1
2
3
4
5
6
7
8
# 检查数据块完整性
hdfs fsck / -files -blocks -locations

# 检查副本数量
hdfs fsck / -files -blocks | grep -E "(Missing|Under-replicated)"

# 检查损坏的数据块
hdfs fsck / -files -blocks | grep -i corrupt

数据恢复

1
2
3
4
5
# 修复损坏的数据块
hdfs fsck / -delete

# 重新平衡副本
hdfs balancer -threshold 1

最佳实践

1. 均衡策略

时间选择

  • 业务低峰期:选择业务访问量最低的时间段
  • 维护窗口:在计划维护期间进行
  • 分批进行:对于大型集群,可以分批进行均衡

参数设置

1
2
3
4
5
6
7
8
# 生产环境推荐参数
hdfs balancer -threshold 5 -policy datanode -idleiterations 3

# 测试环境参数
hdfs balancer -threshold 10 -policy datanode -idleiterations 1

# 紧急情况参数
hdfs balancer -threshold 20 -policy datanode

2. 监控策略

实时监控

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 创建监控脚本
cat > /tmp/balance_monitor.sh << 'EOF'
#!/bin/bash

# 检查均衡进程
if ! pgrep -f "hdfs.*balancer" > /dev/null; then
    echo "$(date): 均衡进程未运行,尝试重启" >> /tmp/balance_monitor.log
    nohup hdfs balancer -threshold 10 > /tmp/balancer.log 2>&1 &
fi

# 检查集群状态
REPORT=$(hdfs dfsadmin -report 2>/dev/null)
if [ $? -ne 0 ]; then
    echo "$(date): HDFS服务异常" >> /tmp/balance_monitor.log
    exit 1
fi

# 计算均衡度
STD_DEV=$(echo "$REPORT" | python3 -c "
import sys
import re

used_percents = []
for line in sys.stdin:
    if 'DFS Used%:' in line:
        percent = float(re.search(r'(\d+\.?\d*)%', line).group(1))
        used_percents.append(percent)

if used_percents:
    avg = sum(used_percents) / len(used_percents)
    variance = sum((x - avg) ** 2 for x in used_percents) / len(used_percents)
    std_dev = variance ** 0.5
    print(f'{std_dev:.2f}')
else:
    print('0')
")

echo "$(date): 当前均衡度: ${STD_DEV}%" >> /tmp/balance_monitor.log

# 如果均衡度过高,启动均衡
if (( $(echo "$STD_DEV > 15" | bc -l) )); then
    echo "$(date): 均衡度过高,启动均衡" >> /tmp/balance_monitor.log
    nohup hdfs balancer -threshold 10 > /tmp/balancer.log 2>&1 &
fi
EOF

chmod +x /tmp/balance_monitor.sh

# 添加到crontab,每30分钟检查一次
echo "*/30 * * * * /tmp/balance_monitor.sh" | crontab -

3. 自动化脚本

完整均衡脚本

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
cat > /tmp/auto_balance.sh << 'EOF'
#!/bin/bash

# 配置参数
THRESHOLD=10
LOG_FILE="/tmp/auto_balance.log"
BALANCE_LOG="/tmp/hdfs_balancer.log"
MAX_RUNTIME=7200  # 最大运行时间(秒)
CHECK_INTERVAL=300  # 检查间隔(秒)

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# 检查HDFS状态
check_hdfs_status() {
    if ! hdfs dfsadmin -report > /dev/null 2>&1; then
        log "错误: HDFS服务不可用"
        exit 1
    fi
    log "HDFS服务状态正常"
}

# 计算均衡度
calculate_balance_degree() {
    local report=$(hdfs dfsadmin -report 2>/dev/null)
    if [ $? -ne 0 ]; then
        echo "0"
        return
    fi

    echo "$report" | python3 -c "
import sys
import re

used_percents = []
for line in sys.stdin:
    if 'DFS Used%:' in line:
        percent = float(re.search(r'(\d+\.?\d*)%', line).group(1))
        used_percents.append(percent)

if used_percents:
    avg = sum(used_percents) / len(used_percents)
    variance = sum((x - avg) ** 2 for x in used_percents) / len(used_percents)
    std_dev = variance ** 0.5
    print(f'{std_dev:.2f}')
else:
    print('0')
"
}

# 启动均衡
start_balancer() {
    log "启动HDFS均衡,阈值: ${THRESHOLD}%"
    nohup hdfs balancer -threshold $THRESHOLD -policy datanode > $BALANCE_LOG 2>&1 &
    BALANCER_PID=$!
    echo $BALANCER_PID > /tmp/balancer.pid
    log "均衡进程已启动,PID: $BALANCER_PID"
}

# 停止均衡
stop_balancer() {
    if [ -f /tmp/balancer.pid ]; then
        local pid=$(cat /tmp/balancer.pid)
        if kill -0 $pid 2>/dev/null; then
            kill $pid
            log "均衡进程已停止,PID: $pid"
        fi
        rm -f /tmp/balancer.pid
    fi
}

# 检查均衡进度
check_balance_progress() {
    local current_degree=$(calculate_balance_degree)
    log "当前均衡度: ${current_degree}%"

    if (( $(echo "$current_degree < 5" | bc -l) )); then
        log "均衡完成!"
        return 0
    else
        return 1
    fi
}

# 主函数
main() {
    log "开始自动均衡流程"

    # 检查HDFS状态
    check_hdfs_status

    # 计算初始均衡度
    initial_degree=$(calculate_balance_degree)
    log "初始均衡度: ${initial_degree}%"

    # 如果已经均衡,退出
    if (( $(echo "$initial_degree < $THRESHOLD" | bc -l) )); then
        log "集群已经均衡,无需执行均衡操作"
        exit 0
    fi

    # 启动均衡
    start_balancer

    # 监控均衡进度
    start_time=$(date +%s)
    while true; do
        current_time=$(date +%s)
        elapsed=$((current_time - start_time))

        # 检查是否超时
        if [ $elapsed -gt $MAX_RUNTIME ]; then
            log "均衡超时,停止均衡进程"
            stop_balancer
            exit 1
        fi

        # 检查均衡进程是否还在运行
        if [ -f /tmp/balancer.pid ]; then
            local pid=$(cat /tmp/balancer.pid)
            if ! kill -0 $pid 2>/dev/null; then
                log "均衡进程异常退出"
                break
            fi
        else
            log "均衡进程PID文件不存在"
            break
        fi

        # 检查均衡进度
        if check_balance_progress; then
            stop_balancer
            log "均衡成功完成"
            exit 0
        fi

        # 等待下次检查
        sleep $CHECK_INTERVAL
    done

    # 清理
    stop_balancer
    log "均衡流程结束"
}

# 信号处理
trap 'log "收到中断信号,停止均衡"; stop_balancer; exit 1' INT TERM

# 执行主函数
main "$@"
EOF

chmod +x /tmp/auto_balance.sh

性能优化建议

1. 系统级优化

网络优化

1
2
3
4
5
6
# 调整网络缓冲区
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.rmem_default = 65536' >> /etc/sysctl.conf
echo 'net.core.wmem_default = 65536' >> /etc/sysctl.conf
sysctl -p

磁盘优化

1
2
3
4
5
6
# 调整I/O调度器
echo noop > /sys/block/sda/queue/scheduler

# 调整I/O参数
echo 1024 > /sys/block/sda/queue/nr_requests
echo 0 > /sys/block/sda/queue/add_random

2. HDFS配置优化

均衡带宽设置

1
2
3
4
5
<!-- hdfs-site.xml -->
<property>
  <name>dfs.datanode.balance.bandwidthPerSec</name>
  <value>52428800</value>  <!-- 50MB/s -->
</property>

复制参数优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- hdfs-site.xml -->
<property>
  <name>dfs.replication</name>
  <value>3</value>
</property>

<property>
  <name>dfs.namenode.replication.work.multiplier.per.iteration</name>
  <value>2</value>
</property>

3. 监控和告警

设置告警

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 创建告警脚本
cat > /tmp/balance_alert.sh << 'EOF'
#!/bin/bash

# 配置参数
ALERT_THRESHOLD=20
EMAIL_LIST="[email protected]"
LOG_FILE="/tmp/balance_alert.log"

# 计算均衡度
STD_DEV=$(hdfs dfsadmin -report | python3 -c "
import sys
import re

used_percents = []
for line in sys.stdin:
    if 'DFS Used%:' in line:
        percent = float(re.search(r'(\d+\.?\d*)%', line).group(1))
        used_percents.append(percent)

if used_percents:
    avg = sum(used_percents) / len(used_percents)
    variance = sum((x - avg) ** 2 for x in used_percents) / len(used_percents)
    std_dev = variance ** 0.5
    print(f'{std_dev:.2f}')
else:
    print('0')
")

# 检查是否需要告警
if (( $(echo "$STD_DEV > $ALERT_THRESHOLD" | bc -l) )); then
    echo "$(date): 警告: HDFS均衡度过高 (${STD_DEV}%)" >> $LOG_FILE

    # 发送邮件告警
    echo "HDFS集群均衡度过高: ${STD_DEV}%" | \
        mail -s "HDFS均衡告警" $EMAIL_LIST

    # 自动启动均衡
    if ! pgrep -f "hdfs.*balancer" > /dev/null; then
        nohup hdfs balancer -threshold 10 > /tmp/balancer.log 2>&1 &
        echo "$(date): 已自动启动均衡进程" >> $LOG_FILE
    fi
fi
EOF

chmod +x /tmp/balance_alert.sh

# 添加到crontab,每小时检查一次
echo "0 * * * * /tmp/balance_alert.sh" | crontab -

总结

HDFS均衡是维护集群健康状态的重要操作。通过合理使用均衡参数、建立完善的监控体系、遵循最佳实践,可以确保集群始终保持良好的数据分布和性能表现。

关键要点:

  1. 及时均衡:在节点使用率差异超过10%时及时进行均衡
  2. 合理参数:根据集群规模和环境选择合适的均衡参数
  3. 持续监控:建立自动化监控和告警机制
  4. 性能优化:从系统、网络、存储等多个层面进行优化
  5. 安全操作:在业务低峰期进行均衡,确保数据安全

通过遵循本指南,您可以有效地管理和维护HDFS集群的数据均衡,确保集群的高可用性和高性能。