未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用范围与待维护事项
本文适用于已掌握HDFS/YARN、HA与Shell的工程人员在隔离测试集群中设计和演练备份恢复,不是可直接执行的生产操作手册。原稿未注明Hadoop版本,旧版hftp迁移、检查点覆盖及强制HA切换均须另行核验。灾备表中的时效、成本和图中延迟是未核实示例,不是可达成承诺。脚本仍缺少失败闭环、目标版本保留和可靠内容验证;单副本、同步删除及跳过Trash操作须先确认独立可恢复备份。
Hadoop数据备份与恢复 - 企业级数据保护策略
abstract 本篇定位
本篇是企业级运维系列第四篇,承接 性能监控与调优,聚焦数据保护这一运维核心命题。一个精心调优的集群,如果没有可靠的数据保护机制,就像一栋没有消防系统的高楼——平时看不出问题,出事时代价惨烈。
目录
HDFS数据备份核心机制
在讨论备份策略之前,先要理解一个基本事实:HDFS 自带三副本机制,在正常运行条件下已具备一定的数据冗余能力。但这种冗余只能应对硬件故障,无法应对以下场景:
- 逻辑删除(误操作
rm -r) - 集群整体故障(如机房断电、网络分区)
- 软件 Bug 导致的数据损坏
- 勒索软件攻击
因此,企业级数据保护需要在三副本之外,建立独立的备份体系。
%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TD
classDef default fill:#FDFBF5,stroke:#6E6A60,color:#2D2A26,stroke-width:1.5px
classDef startend fill:#2D2A26,stroke:#2D2A26,color:#FDFBF5,font-weight:bold
classDef decision fill:#F6EAD8,stroke:#C08A1A,color:#2D2A26,font-weight:bold
classDef hub fill:#3B5A80,stroke:#3B5A80,color:#FDFBF5,font-weight:bold
classDef io fill:#E5EAF0,stroke:#3B5A80,color:#2D2A26
classDef accent fill:#A6432C,stroke:#A6432C,color:#FDFBF5,font-weight:bold
classDef storage fill:#F3EEDF,stroke:#9A9488,color:#2D2A26
A[数据保护层次] --> B[副本冗余 - 硬件故障防护]
A --> C[快照 - 逻辑错误回滚]
A --> D[跨集群备份 - 灾难恢复]
A --> E[归档存储 - 长期保留]
B --> B1[dfs.replication=3]
C --> C1[hdfs dfs -createSnapshot]
D --> D1[distcp 增量复制]
E --> E1[冷存储 / 对象存储]
class A,B,C,D,E,B1,C1,D1,E1 default
distcp跨集群复制
distcp(Distributed Copy)是 Hadoop 内置的跨集群数据复制工具,本质上是一个 MapReduce 任务,将数据并行地从源集群传输到目标集群。
note 为什么不用普通的 cp 或 scp?
普通 cp 或 scp 不具备 distcp 这样的分布式任务调度能力。distcp 将文件列表分片,用多个 Map 任务并行传输;实际吞吐受网络、源目标存储、文件分布和并发配置限制,不保证随节点数线性提升。
基础语法
# 全量复制:将生产集群的 /data/warehouse 复制到灾备集群
hadoop distcp \
hdfs://prod-cluster:8020/data/warehouse \
hdfs://dr-cluster:8020/data/warehouse
# 指定带宽限制(单位 MB/s),避免占满网络
hadoop distcp \
-bandwidth 100 \
hdfs://prod-cluster:8020/data/warehouse \
hdfs://dr-cluster:8020/data/warehouse
# 增量同步:复制缺失或按比较规则判定不同的文件;-delete还会删除目标端多余文件,可能传播源端误删
hadoop distcp \
-update \
-delete \
hdfs://prod-cluster:8020/data/warehouse \
hdfs://dr-cluster:8020/data/warehouse
关键参数说明
| 参数 | 含义 | 使用场景 |
|---|---|---|
-update |
复制目标端缺失或按文件大小、校验和等适用比较规则判定不同的文件,不只比较大小 | 增量同步;比较行为需核对版本及校验选项 |
-delete |
删除目标端源端没有的文件 | 保持目标与源严格一致 |
-overwrite |
强制覆盖目标端所有文件 | 全量重建备份 |
-bandwidth N |
限制每个 Map 的带宽为 N MB/s | 生产高峰期避免影响业务 |
-m N |
指定 Map 任务数量 | 控制并发度,默认 20 |
-skipcrccheck |
跳过部分CRC校验比较,不等于跳过所有完整性检查 | 仅在明确校验差异原因并具备替代内容验证时使用,不应因块大小不同而直接启用 |
-atomic |
原子性复制(全部成功才生效) | 对一致性要求严格的场景 |
-strategy dynamic |
动态任务分配策略 | 文件大小差异极大时效率更高 |
跨 Hadoop 版本复制
# 老集群(Hadoop 1.x)到新集群(Hadoop 2.x/3.x)迁移
hadoop distcp \
-Dmapreduce.job.hdfs-servers=hdfs://old-cluster:9000 \
hftp://old-cluster:50070/data/legacy \
hdfs://new-cluster:8020/data/migrated
warning distcp 的注意事项
- distcp 的 MapReduce 任务运行在提交配置所指向的计算集群,不必是目标集群;任务节点必须能访问源和目标文件系统
- 跨版本复制须核对客户端、服务端协议及认证兼容性;上面的
hftp://命令是历史版本示例,不能作为 Hadoop 2.x/3.x 间迁移的通用方案 - 跨数据中心复制时,网络延迟会成为瓶颈,建议配合
-bandwidth参数精细控制
快照机制
HDFS 快照是某一时刻文件系统状态的只读视图。创建时不复制实际数据块,主要记录元数据,因此通常开销较低;但后续删除或修改可能使旧数据块因快照引用而继续占用空间,不能将总存储开销理解为仅有元数据变化量,创建耗时也不保证为毫秒级。
启用快照功能
# 管理员开启指定目录的快照功能(必须先开启才能创建快照)
hdfs dfsadmin -allowSnapshot /data/warehouse
# 关闭快照功能(必须先删除所有快照)
hdfs dfsadmin -disallowSnapshot /data/warehouse
快照生命周期管理
# 创建快照(不指定名称时自动生成时间戳名称)
hdfs dfs -createSnapshot /data/warehouse daily-2026-03-21
# 列出目录下的所有快照
hdfs dfs -ls /data/warehouse/.snapshot
# 查看快照内容(可以像普通目录一样浏览)
hdfs dfs -ls /data/warehouse/.snapshot/daily-2026-03-21/
# 对比两个快照之间的差异(用于审计变化)
hdfs snapshotDiff /data/warehouse daily-2026-03-20 daily-2026-03-21
# 删除快照
hdfs dfs -deleteSnapshot /data/warehouse daily-2026-03-21
快照差异输出解读
M ./sales/orders_2026_03_21.parquet # M = 文件被修改
+ ./sales/returns_2026_03_21.parquet # + = 文件被新增
- ./sales/temp_staging.csv # - = 文件被删除
R ./archive -> ./archive_old # R = 文件被重命名
tip 快照的最佳实践
- 快照保留策略建议:每日快照保留 7 天,每周快照保留 4 周,每月快照保留 12 个月
- 快照本身不能替代跨集群备份,它只防逻辑错误,不防集群整体故障
- 对写入频繁的目录(如 Kafka 数据目录)谨慎使用快照,快照元数据开销会随变化量增大
副本策略配置
HDFS 的副本放置策略直接影响数据的可靠性和读取性能。
默认副本放置策略(机架感知)
副本1: Writer位于符合条件的DataNode时优先本地放置;外部客户端写入时由策略选择合适的DataNode
副本2: 与副本1不同机架的随机节点
副本3: 与副本2相同机架的不同节点
调整副本数量
# 针对特定目录调整副本数(重要数据使用更高副本数)
hdfs dfs -setrep -R 5 /data/critical/
# 仅在已有独立且已验证可恢复备份时考虑降低归档数据副本数;单副本无法容忍该副本丢失
hdfs dfs -setrep -R 1 /data/archive/cold/
# 查看当前副本状态
hdfs fsck /data/critical/ -files -blocks -racks
全局副本数配置(hdfs-site.xml)
<property>
<name>dfs.replication</name>
<value>3</value>
<description>默认副本数,生产环境建议保持3</description>
</property>
机架感知配置(core-site.xml)
<property>
<name>net.topology.script.file.name</name>
<value>/etc/hadoop/conf/rack-topology.sh</value>
</property>
#!/bin/bash
# rack-topology.sh 示例:根据 IP 返回机架标识
for IP in "$@"; do
case "$IP" in
10.1.1.*) echo "/dc1/rack1" ;;
10.1.2.*) echo "/dc1/rack2" ;;
10.2.1.*) echo "/dc2/rack1" ;;
*) echo "/default/rack0" ;;
esac
done
数据恢复场景与操作
NameNode元数据恢复
NameNode 是 HDFS 的大脑,存储所有文件和目录的元数据。NameNode 故障通常是最严重的事故。
元数据文件结构
${dfs.namenode.name.dir}/
├── current/
│ ├── fsimage_0000000000012345678 # 文件系统快照(完整状态)
│ ├── fsimage_0000000000012345678.md5
│ ├── edits_0000000000012345679-... # 历史编辑日志
│ ├── edits_inprogress_0000000000013000000 # 当前编辑日志
│ └── VERSION
场景一:NameNode 进程崩溃(元数据完好)
# 直接重启即可,fsimage 和 edits 会自动合并
hadoop-daemon.sh start namenode
# 观察启动日志,确认 fsimage 加载成功
tail -f /var/log/hadoop/hadoop-hdfs-namenode-*.log \
| grep -E "loaded|checkpoint|started"
场景二:fsimage 损坏(有备份)
# 第一步:停止 NameNode
hadoop-daemon.sh stop namenode
# 第二步:仅针对使用SecondaryNameNode的非HA部署评估检查点恢复
# SecondaryNameNode 的检查点在 dfs.namenode.checkpoint.dir
# 执行下方覆盖命令前,须离线备份current并校验集群标识、检查点事务号及后续edits连续性
# 此片段不是完整恢复规程;不满足上述条件时不得覆盖
rsync -av secondary-namenode:/hadoop/namesecondary/current/ \
/hadoop/namenode/current/
# 第三步:以恢复模式启动(交互式,选择最佳恢复方案)
hdfs namenode -recover
# 第四步:正常启动
hadoop-daemon.sh start namenode
场景三:高可用模式下的 NameNode 切换
# 查看当前 HA 状态
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
# 手动触发 Standby 切换为 Active
hdfs haadmin -failover nn1 nn2
# 强制切换示例:无响应不等于已隔离;须先确认旧Active已可靠fencing并核对自动故障转移配置,禁止直接照抄执行
hdfs haadmin -failover --forcefence --forceactive nn1 nn2
warning NameNode 恢复的黄金原则
- 高可用集群中,绝对不要同时操作两个 NameNode,脑裂(split-brain)会导致数据损坏
- 恢复前务必备份当前的 fsimage 和 edits 文件,防止恢复操作本身造成二次破坏
- 使用
-recover参数时,Hadoop 会尝试自动恢复,但可能丢失最近的写入操作
DataNode数据块恢复
DataNode 故障相对 NameNode 更为常见,恢复过程也更为系统化。
# 检查 DataNode 状态(哪些节点不可用)
hdfs dfsadmin -report | grep -A 5 "Dead datanodes"
# 检查数据块健康状况(关注 CORRUPT FILES 和 MISSING BLOCKS)
hdfs fsck / -blocks -locations 2>&1 | grep -E "Status:|CORRUPT|MISSING|Total"
# 退役仍可读取数据的DataNode;已失联节点不能通过退役迁出不可读取的数据,需依赖其他健康副本补足
# 步骤1:确认hdfs-site.xml中的dfs.hosts.exclude指向下列文件,并检查剩余健康副本及容量,再加入排除列表
echo "datanode-05.example.com" >> /etc/hadoop/conf/dfs.exclude
# 步骤2:刷新 NameNode 的节点列表
hdfs dfsadmin -refreshNodes
# 步骤3:监控退役进度(等待 Decommission Status 变为 Decommissioned)
watch -n 30 "hdfs dfsadmin -report | grep -A 3 'datanode-05'"
误删文件恢复
HDFS 的 Trash 机制是应对误操作的第一道防线,类似操作系统的回收站。
Trash 机制配置(core-site.xml)
<property>
<name>fs.trash.interval</name>
<value>10080</value>
<!-- 回收站保留时间(分钟),10080 = 7天,生产环境建议至少7天 -->
</property>
<property>
<name>fs.trash.checkpoint.interval</name>
<value>60</value>
<!-- 定期清理回收站过期文件的间隔(分钟) -->
</property>
从 Trash 恢复文件
# 查看回收站内容(每个用户有独立的回收站路径)
hdfs dfs -ls /user/hadoop/.Trash/Current/
# 恢复误删文件(从回收站移回原位置)
hdfs dfs -mv \
/user/hadoop/.Trash/Current/data/warehouse/sales/orders_2026_03_20.parquet \
/data/warehouse/sales/
# 如果 Trash 已过期,从快照恢复
hdfs dfs -cp \
/data/warehouse/.snapshot/daily-2026-03-20/sales/orders_2026_03_20.parquet \
/data/warehouse/sales/
tip Trash 机制的局限性
- 使用
-skipTrash参数删除的文件会绕过回收站,无法通过此方式恢复 - Trash 保留期过后,文件被永久删除,此时只能依赖快照或跨集群备份
- Trash 保护的是逻辑删除,物理节点故障导致的数据丢失需要副本机制保护
企业级灾备方案设计
同城双活与异地灾备
三种主流灾备架构对比
下表时效和成本为原稿未核实的教学示例,不是拓扑天然具备的能力或固定成本排序;须结合复制机制、规模、故障范围和恢复演练重新评估。
| 方案 | 拓扑结构 | RTO | RPO | 成本 | 适用场景 |
|---|---|---|---|---|---|
| 同城双活 | 两个数据中心同时承载业务 | 秒级 | 接近零 | 最高 | 金融、电信核心系统 |
| 同城冷备 | 主集群运行,备集群待机 | 分钟~小时级 | 分钟级 | 适中 | 互联网中型平台 |
| 异地灾备 | 主备跨地域,异步复制 | 小时级 | 分钟~小时级 | 最低 | 合规要求、超大规模平台 |
同城主写、备端只读的数据同步示例
下图不是双端同时写入架构;图中的“延迟 < 5min”为原稿未核实的示例目标,distcp异步复制本身不保证该延迟或零数据丢失。
%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph LR
classDef default fill:#FDFBF5,stroke:#6E6A60,color:#2D2A26,stroke-width:1.5px
classDef startend fill:#2D2A26,stroke:#2D2A26,color:#FDFBF5,font-weight:bold
classDef decision fill:#F6EAD8,stroke:#C08A1A,color:#2D2A26,font-weight:bold
classDef hub fill:#3B5A80,stroke:#3B5A80,color:#FDFBF5,font-weight:bold
classDef io fill:#E5EAF0,stroke:#3B5A80,color:#2D2A26
classDef accent fill:#A6432C,stroke:#A6432C,color:#FDFBF5,font-weight:bold
classDef storage fill:#F3EEDF,stroke:#9A9488,color:#2D2A26
subgraph DC1[数据中心 1 - 主]
P1[Primary HDFS]
W1[业务写入]
W1 --> P1
end
subgraph DC2[数据中心 2 - 备]
P2[Secondary HDFS]
R2[只读查询]
P2 --> R2
end
P1 -->|distcp 增量同步\n延迟 < 5min| P2
class DC1,P1,W1,DC2,P2,R2 default
跨数据中心的 distcp 配置
# 配置跨数据中心复制,限制带宽避免占满专线
hadoop distcp \
-bandwidth 50 \
-m 10 \
-update \
-log /data/distcp_logs/dr-sync-$(date +%Y%m%d%H%M) \
hdfs://prod-dc1:8020/data/warehouse \
hdfs://dr-dc2:8020/data/warehouse
RTO与RPO指标
这是灾备方案设计中最重要的两个指标,务必在方案设计阶段与业务方明确约定。
note 核心定义
RTO(Recovery Time Objective,恢复时间目标):从故障发生到业务恢复正常所允许的最长时间。
RPO(Recovery Point Objective,恢复点目标):故障发生时,业务能接受的最大数据丢失时间窗口。
简单记忆:RTO 关注恢复速度,RPO 关注数据损失量。
不同业务场景的 RTO/RPO 参考
下表保留原稿数值作为教学目标示例,不代表行业统一要求或已验证能力;“零丢失”等目标必须明确故障范围、写入确认与复制语义,并以演练验证。
| 业务类型 | RTO 要求 | RPO 要求 | 建议方案 |
|---|---|---|---|
| 实时交易数据 | 小于 1 分钟 | 零丢失 | 同城双活 + 同步复制 |
| 核心数仓 | 小于 30 分钟 | 小于 5 分钟 | 同城双活 + 异步复制 |
| 历史分析数据 | 小于 4 小时 | 小于 1 小时 | 同城冷备 + 定时 distcp |
| 归档数据 | 小于 24 小时 | 小于 24 小时 | 异地灾备 + 每日备份 |
warning 灾备方案必须定期演练
纸面上的 RTO 不等于实际恢复时间。建议每季度进行一次灾备切换演练,验证实际 RTO 是否满足目标。未经演练的灾备方案,其实际恢复能力尚未得到验证,不能据纸面设计作出可靠恢复承诺。
自动化备份脚本
以下是用于隔离测试环境的自动化备份脚本示例,集成了快照创建、增量复制、文件数初筛和源端快照保留策略。它尚缺少完整失败处理、目标备份版本保留及可靠内容验证,不能直接用于生产环境。
#!/bin/bash
# =============================================================
# HDFS 自动化备份脚本
# 功能:快照创建 + distcp 增量备份 + 文件数校验 + 过期清理
# 部署:crontab -e 添加 "0 2 * * * /opt/scripts/hdfs_backup.sh"
# =============================================================
# ---------- 配置区(按实际环境修改) ----------
SOURCE_CLUSTER="hdfs://prod-namenode:8020"
TARGET_CLUSTER="hdfs://dr-namenode:8020"
SOURCE_DIR="/data/warehouse"
TARGET_DIR="/data/warehouse"
SNAPSHOT_RETAIN_DAYS=7
BACKUP_LOG_DIR="/var/log/hdfs-backup"
ALERT_EMAIL="ops-team@example.com"
DISTCP_MAPPERS=20
DISTCP_BANDWIDTH=100 # MB/s,每个 Map 的带宽上限
# --------------------------------------------
DATE=$(date +%Y%m%d_%H%M%S)
SNAPSHOT_NAME="auto-backup-${DATE}"
LOG_FILE="${BACKUP_LOG_DIR}/backup-${DATE}.log"
mkdir -p "${BACKUP_LOG_DIR}"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"; }
send_alert() {
log "ALERT: $1"
echo "$2" | mail -s "[HDFS备份告警] $1" "${ALERT_EMAIL}" 2>/dev/null \
|| log "邮件发送失败,请检查 MTA 配置"
}
# --- 步骤1:创建快照 ---
log "===== 开始备份任务:${SNAPSHOT_NAME} ====="
log "步骤1:在源集群创建快照"
hdfs dfs -createSnapshot "${SOURCE_CLUSTER}${SOURCE_DIR}" "${SNAPSHOT_NAME}" >> "${LOG_FILE}" 2>&1
if [ $? -ne 0 ]; then
send_alert "快照创建失败" \
"集群 ${SOURCE_CLUSTER} 目录 ${SOURCE_DIR} 快照创建失败,详见 ${LOG_FILE}"
exit 1
fi
log "快照创建成功:${SOURCE_DIR}/.snapshot/${SNAPSHOT_NAME}"
# --- 步骤2:distcp 增量复制 ---
log "步骤2:执行 distcp 增量备份到灾备集群"
hadoop distcp \
-update \
-m "${DISTCP_MAPPERS}" \
-bandwidth "${DISTCP_BANDWIDTH}" \
-log "${BACKUP_LOG_DIR}/distcp-log-${DATE}" \
"${SOURCE_CLUSTER}${SOURCE_DIR}/.snapshot/${SNAPSHOT_NAME}" \
"${TARGET_CLUSTER}${TARGET_DIR}" \
>> "${LOG_FILE}" 2>&1
if [ $? -ne 0 ]; then
send_alert "distcp 备份失败" \
"distcp 任务异常退出,详见 ${LOG_FILE}"
exit 2
fi
log "distcp 备份完成"
# --- 步骤3:文件数一致性校验 ---
log "步骤3:校验备份数据完整性"
SOURCE_COUNT=$(hdfs dfs -count "${SOURCE_CLUSTER}${SOURCE_DIR}/.snapshot/${SNAPSHOT_NAME}" \
2>/dev/null | awk '{print $2}')
TARGET_COUNT=$(hdfs dfs -count "${TARGET_CLUSTER}${TARGET_DIR}" \
2>/dev/null | awk '{print $2}')
log "源端文件数:${SOURCE_COUNT},目标端文件数:${TARGET_COUNT}"
if [ "${SOURCE_COUNT}" != "${TARGET_COUNT}" ]; then
send_alert "文件数不一致" \
"源端 ${SOURCE_COUNT} 个,目标端 ${TARGET_COUNT} 个,请检查 distcp 日志"
fi
SOURCE_SIZE=$(hdfs dfs -du -s -h "${SOURCE_CLUSTER}${SOURCE_DIR}/.snapshot/${SNAPSHOT_NAME}" \
2>/dev/null | awk '{print $1,$2}')
TARGET_SIZE=$(hdfs dfs -du -s -h "${TARGET_CLUSTER}${TARGET_DIR}" \
2>/dev/null | awk '{print $1,$2}')
log "源端数据量:${SOURCE_SIZE},目标端数据量:${TARGET_SIZE}"
# --- 步骤4:清理过期快照 ---
log "步骤4:清理超过 ${SNAPSHOT_RETAIN_DAYS} 天的快照"
# 计算截止日期(兼容 Linux 和 macOS)
CUTOFF_DATE=$(date -d "${SNAPSHOT_RETAIN_DAYS} days ago" +%Y%m%d 2>/dev/null \
|| date -v -${SNAPSHOT_RETAIN_DAYS}d +%Y%m%d)
hdfs dfs -ls "${SOURCE_CLUSTER}${SOURCE_DIR}/.snapshot" 2>/dev/null \
| grep "auto-backup-" \
| awk '{print $NF}' \
| while read SNAP_PATH; do
SNAP_NAME=$(basename "${SNAP_PATH}")
SNAP_DATE=$(echo "${SNAP_NAME}" | grep -oE '[0-9]{8}' | head -1)
if [ -n "${SNAP_DATE}" ] && [ "${SNAP_DATE}" -lt "${CUTOFF_DATE}" ]; then
log "删除过期快照:${SNAP_NAME}"
hdfs dfs -deleteSnapshot "${SOURCE_CLUSTER}${SOURCE_DIR}" "${SNAP_NAME}" \
>> "${LOG_FILE}" 2>&1
fi
done
# --- 清理过期日志文件(保留 30 天)---
find "${BACKUP_LOG_DIR}" -name "backup-*.log" -mtime +30 -delete
log "===== 备份任务完成:${SNAPSHOT_NAME} ====="
exit 0
配置定时任务
# 以 hdfs 用户身份编辑 crontab
sudo -u hdfs crontab -e
# 添加以下条目(每天凌晨 2:00 执行,业务低峰期)
0 2 * * * /opt/scripts/hdfs_backup.sh >> /var/log/hdfs-backup/cron.log 2>&1
备份数据完整性验证
备份的价值在于能够可靠地恢复,因此验证备份的完整性是备份流程不可缺少的环节。
层次一:文件数量和数据量对比
#!/bin/bash
# 快速完整性检查脚本
SOURCE="hdfs://prod-namenode:8020/data/warehouse"
TARGET="hdfs://dr-namenode:8020/data/warehouse"
echo "=== 文件数量对比 ==="
echo "源端:$(hdfs dfs -count ${SOURCE} | awk '{print $2}') 个文件"
echo "目标:$(hdfs dfs -count ${TARGET} | awk '{print $2}') 个文件"
echo "=== 数据量对比 ==="
echo "源端:$(hdfs dfs -du -s -h ${SOURCE} | awk '{print $1,$2}')"
echo "目标:$(hdfs dfs -du -s -h ${TARGET} | awk '{print $1,$2}')"
层次二:HDFS fsck 块级健康校验
# 在灾备集群运行 fsck,确认数据块完整性
hdfs fsck /data/warehouse -files -blocks 2>&1 \
| grep -E "Status:|CORRUPT|MISSING|Total blocks"
# 期望的正常输出:
# Status: HEALTHY
# Total blocks: 204800 (avg. block size 5242880 B)
# UNDER_REPLICATED blocks: 0
# CORRUPT FILES: 0
# MISSING BLOCKS: 0
层次三:抽样文件 CRC 校验
HDFS文件校验值可能受块布局、每块校验配置及组合方式影响;跨集群不相等不一定意味着内容损坏,应先确认校验条件可比,必要时使用独立内容摘要。以下抽样仅作初筛,须包含零字节文件、核对实际样本数并显式指定源集群。
#!/bin/bash
# 随机抽取若干文件,对比源端和目标端的 CRC 校验值
SAMPLE_COUNT=20
SOURCE_BASE="hdfs://prod-namenode:8020"
TARGET_BASE="hdfs://dr-namenode:8020"
hdfs dfs -ls -R /data/warehouse/ 2>/dev/null \
| awk '$5 > 0 {print $NF}' \
| shuf | head -${SAMPLE_COUNT} > /tmp/sample_files.txt
FAIL_COUNT=0
while read FILE_PATH; do
SRC_CRC=$(hdfs dfs -checksum "${SOURCE_BASE}${FILE_PATH}" 2>/dev/null \
| awk '{print $NF}')
TGT_CRC=$(hdfs dfs -checksum "${TARGET_BASE}${FILE_PATH}" 2>/dev/null \
| awk '{print $NF}')
if [ "${SRC_CRC}" = "${TGT_CRC}" ] && [ -n "${SRC_CRC}" ]; then
echo "OK ${FILE_PATH}"
else
echo "FAIL ${FILE_PATH}"
FAIL_COUNT=$((FAIL_COUNT + 1))
fi
done < /tmp/sample_files.txt
echo ""
echo "抽样校验结果:共 ${SAMPLE_COUNT} 个文件,${FAIL_COUNT} 个校验不通过"
[ ${FAIL_COUNT} -eq 0 ] && exit 0 || exit 1
层次四:业务可用性验证(恢复演练)
# 每月从灾备集群恢复一个非关键分区,验证完整恢复流程
RESTORE_TEST_DIR="/tmp/dr-restore-test-$(date +%Y%m%d)"
# 从灾备集群复制数据到生产集群的临时目录
hadoop distcp \
hdfs://dr-namenode:8020/data/warehouse/test_partition/ \
hdfs://prod-namenode:8020${RESTORE_TEST_DIR}/
# 验证数据可被查询引擎读取
hive -e "
CREATE EXTERNAL TABLE IF NOT EXISTS restore_verify
LIKE sales_orders
LOCATION '${RESTORE_TEST_DIR}';
SELECT COUNT(*) FROM restore_verify;
DROP TABLE restore_verify;
"
# 清理临时数据
hdfs dfs -rm -r -skipTrash ${RESTORE_TEST_DIR}
echo "恢复演练完成"
tip 备份验证的四个维度
完整的备份验证需要覆盖:文件数量是否一致、数据块是否健康、文件内容是否一致、业务逻辑是否可用。最可靠的验证是定期进行实际恢复演练,而不是仅仅检查备份文件是否存在。
掌握检查与实践练习
掌握检查
完成本篇学习后,请确认你能够回答以下问题:
- [ ] 能够区分 HDFS 三副本、快照、跨集群备份三种机制的适用场景和各自的局限性
- [ ] 能够独立编写 distcp 命令完成全量备份和增量同步,并正确使用
-update、-bandwidth、-m等关键参数 - [ ] 能够在 NameNode 元数据损坏时,按步骤完成恢复操作(区分 HA 和非 HA 两种情况)
- [ ] 能够解释 RTO 和 RPO 的含义,并根据业务需求选择合适的灾备方案
- [ ] 能够设计并实现包含快照、增量复制、完整性校验、过期清理的自动化备份方案
实践练习
练习一:完整备份链路搭建
在你的测试集群中完成以下操作序列:
- 对
/test/data目录启用快照功能,创建名为baseline的快照 - 向
/test/data写入若干文件,再创建名为increment-01的快照 - 使用
hdfs snapshotDiff查看两个快照之间的文件变化列表 - 使用 distcp 将
increment-01快照内容同步到另一个目录/test/data-backup - 在源目录中删除一个文件,再从
increment-01快照中恢复该文件
练习二:灾备方案设计
给定以下业务场景,设计完整的灾备方案(需明确 RTO/RPO 目标、备份频率、验证机制、成本说明):
某互联网公司的数据仓库存储了 500TB 的用户行为数据,每天新增约 2TB。该数据主要用于 T+1 离线分析报表,核心报表延误时业务可接受最多 4 小时的恢复时间。公司预算仅支持同城灾备,没有异地灾备条件。请设计完整的灾备方案,并说明每个技术选型的理由。
学习路径
本篇完成了企业级运维系列的数据保护部分,下一篇进入整个系列的终结篇:
故障排查与运维 - 系统化故障诊断方法论、HDFS/YARN/MR 常见故障处理、运维自动化实践
tip 关键收获
- HDFS 三副本应对硬件故障,快照应对逻辑错误,跨集群备份应对灾难性事故,三者缺一不可
- distcp 是跨集群数据复制的核心工具,掌握
-update、-bandwidth、-m参数是运维必备技能 - RTO 和 RPO 是灾备方案的核心约束,务必在方案设计初期与业务方明确对齐,而不是技术团队单方面决定
- 从未经过演练的灾备方案,在真实故障中几乎不可信赖