大数据生产运维实战
一、HDFS 核心运维
1.1 集群存储状态快速诊断
场景: 凌晨告警:HDFS 写入失败 / 磁盘告警 / DataNode 掉线,可用这组命令定位
注意: Missing Blocks > 0 时立即停止写入相关目录,先执行 fsck 定位再决策;盲目重启会加重元数据损坏
# 1. 总览:DataNode 数量 / 可用空间 / 丢失块
hdfs dfsadmin -report | grep -E 'Live|Dead|Missing|DFS Used'
# 2. 文件系统完整性检查(有 Missing Block 立即执行)
hdfs fsck / -list-corruptfileblocks 2>/dev/null | head -30
# 3. 各 DataNode 磁盘使用详情
hdfs dfsadmin -report | awk '/^Name/{dn=$2} /Used/{print dn, $0}'
# 4. 查看 NameNode 内存(元数据对象数 × 150B ≈ NN 内存需求)
hdfs dfsadmin -report | grep 'Files and Directories'
1.2 磁盘空间告急处理(80% 阈值触发)
场景: DataNode 使用率 > 80%,HDFS 写入变慢;> 90% 触发 HDFS 只读保护
最佳实践: 生产建议:设置 dfs.datanode.du.reserved(预留 10% 磁盘给 OS),避免触发 OOM Killer
# 步骤1:定位最大目录
hdfs dfs -du -s -h /* | sort -rh | head -20
# 步骤2:检查 HDFS 回收站占用(大量旧数据可能在此)
hdfs dfs -du -s -h /user/*/. trash
hdfs dfs -expunge # 立即清空回收站
# 步骤3:降低非关键数据副本数(临时释放空间)
hdfs dfs -setrep -R -w 2 /warehouse/tmp # 将副本从3改为2
# 步骤4:均衡数据(扩容后必做,避免新节点空闲)
hdfs balancer -threshold 10 & # 后台运行,10%阈值
1.3 NameNode 安全模式(Safe Mode)处理
场景: 集群重启后作业无法运行,HDFS 提示 'Name node is in safe mode'
说明: Safe Mode 触发条件:块可用率 < dfs.namenode.safemode.threshold-pct(默认0.999)。集群扩容后副本复制完成前会触发,属正常现象,等待即可
# 查看安全模式状态及块恢复进度
hdfs dfsadmin -safemode get
hdfs dfsadmin -report | grep 'Under replicated'
# 等块恢复完自动退出(正常情况);或手动强制退出(谨慎)
hdfs dfsadmin -safemode leave # 仅在确认块完整后执行
1.4 NameNode HA 故障切换
场景: Active NameNode 进程崩溃 / 节点宕机,需要手动或自动切换到 Standby
注意: 强制切换前必须确认旧 Active 已完全停止(fencing),否则双 Active 会导致元数据脑裂,数据损坏无法恢复
# 查看当前 HA 状态
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
# 手动切换(原Active已彻底宕机的情况)
hdfs haadmin -failover --forcefence nn1 nn2
# 切换后验证
hdfs dfsadmin -report | head -5
hdfs haadmin -checkHealth nn2
1.5 数据误删除恢复
场景: 用户执行 hdfs dfs -rm -r 删除了重要数据,需要从回收站恢复
最佳实践: 对关键目录(如 Hive warehouse)启用快照保护:hdfs dfsadmin -allowSnapshot /warehouse && hdfs dfs -createSnapshot /warehouse daily_$(date +%Y%m%d)
# 查看回收站内容(回收站路径:/user/<username>/.Trash/Current/)
hdfs dfs -ls /user/hdfs/.Trash/Current/
# 恢复文件
hdfs dfs -mv /user/hdfs/.Trash/Current/warehouse/important /warehouse/important
# 如果回收站已清空,尝试从快照恢复
hdfs dfs -ls /data/.snapshot/ # 列出可用快照
hdfs dfs -cp /data/.snapshot/snap1/file /data/file # 从快照恢复
二、YARN 资源与作业管理
2.1 资源配置黄金公式
场景: 新节点上线或内存告警时,快速计算 YARN 资源分配参数
注意: yarn.nodemanager.vmem-pmem-ratio 默认2.1,即申请1GB物理内存可用2.1GB虚拟内存。JVM GC行为可能导致虚拟内存超限被 Kill,生产建议设为2.5或关闭虚拟内存检查
| 参数 | 计算方法 | 128GB/32核示例 |
|
yarn.nodemanager.resource.memory-mb |
总内存 - OS预留(8GB) - 其他服务(4GB) |
116736 MB (~114GB) |
|
yarn.nodemanager.resource.cpu-vcores |
物理核数(超线程关闭时)或 核数×1.5 |
32 或 48 |
|
yarn.scheduler.minimum-allocation-mb |
单Container最小内存,建议1024或2048 |
2048 |
|
yarn.scheduler.maximum-allocation-mb |
单Container最大内存 ≤ NM总内存 |
32768 (32GB) |
|
mapreduce.map.memory.mb |
建议 minimum-allocation × 1 |
2048 |
|
mapreduce.reduce.memory.mb |
建议 minimum-allocation × 2 |
4096 |
|
mapreduce.map.java.opts |
container内存的75%(预留25%给JVM overhead) |
-Xmx1536m |
2.2 作业卡死 / 队列积压处理
场景: 作业长时间 ACCEPTED 状态、或某队列积压大量 Pending 作业
最佳实践: Capacity Scheduler 启用抢占(preemption):yarn.scheduler.capacity.preemption.enabled=true,防止低优先级队列长期占用高优先级队列资源
# 1. 查看当前所有运行/等待中的作业
yarn application -list -appStates RUNNING,ACCEPTED | head -30
# 2. 查看队列资源使用情况
yarn queue -status root.prod
# 3. 查看各节点状态(是否有不健康节点导致资源减少)
yarn node -list -states ALL | grep -v RUNNING
# 4. 快速定位占用资源最多的作业
yarn application -list -appStates RUNNING | sort -k8 -rn | head -10
# 5. Kill 占用过多资源的作业(协调业务方后执行)
yarn application -kill application_1234567890_0001
2.3 节点上下线操作(标准流程)
场景: DataNode / NodeManager 节点需要维护(系统升级、硬件更换)
注意: 切勿直接关机:未完成 decommission 直接断节点会导致 Under-replicated 甚至 Missing Blocks,副本恢复需消耗大量带宽
# 下线流程(3步,顺序执行):
# Step 1: 加入排除列表(graceful decommission)
echo 'worker-03.prod.com' >> $HADOOP_CONF_DIR/dfs.exclude
echo 'worker-03.prod.com' >> $HADOOP_CONF_DIR/yarn.exclude
# Step 2: 刷新配置(无需重启服务)
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes
# Step 3: 等待 Decommissioned 完成(数据迁移中状态为 Decommission In Progress)
watch -n30 'hdfs dfsadmin -report | grep -A3 worker-03'
# 重新上线:
sed -i '/worker-03/d' $HADOOP_CONF_DIR/dfs.exclude
hdfs dfsadmin -refreshNodes && yarn rmadmin -refreshNodes
三、Spark 生产调优实战
3.1 Spark 作业提交标准模板
场景: 新作业上线,合理设置资源参数,避免资源浪费或不足
说明: num-executors × executor-cores = 总并行度基数。spark.default.parallelism 建议为总核数的 3-4 倍
# 生产推荐:yarn-cluster 模式(Driver 在集群内,Driver 挂了可自动重试)
spark-submit \
--master yarn \
--deploy-mode cluster \
--name 'order_etl_daily' \
--queue prod \ # 指定队列,隔离资源
--num-executors 20 \ # Executor 数量
--executor-cores 4 \ # 每个Executor的核数(2-5之间)
--executor-memory 8g \ # Executor堆内存
--conf spark.executor.memoryOverhead=1g \ # 堆外内存(≥ executor-memory × 10%)
--conf spark.driver.memory=4g \
--conf spark.driver.memoryOverhead=512m \
--conf spark.default.parallelism=320 \ # 总核数(20×4=80) × 4
--conf spark.sql.shuffle.partitions=320 \
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \
--conf spark.dynamicAllocation.enabled=false \ # 批处理建议固定资源
myapp.jar
3.2 数据倾斜处理(最高频性能问题)
场景: Spark 作业 99% Task 完成后某个 Task 卡很久,或 OOM 频繁发生在特定节点
注意: 不要用 repartition 解决倾斜(只是把数据洗牌,不改变 Key 分布)。spark.sql.shuffle.partitions 从默认200调大也无效,根因在于 Key 分布不均
# 诊断:打开 Spark UI → Stages → 看各 Task Duration 分布
# 诊断倾斜的 Key
df.groupBy('skew_key').count().orderBy(desc('count')).show(20)
# 方案一:加盐打散(彻底解决)
# 写入端:Key 加随机前缀
val salted = df.withColumn('salted_key',concat(col('key'), lit('_'), (rand() * 100).cast(IntegerType)))
# 读取端:去盐
val result = salted.withColumn('key', split(col('salted_key'), '_')(0))
# 方案二:Broadcast Join(小表 < 200MB 时优先用)
import org.apache.spark.sql.functions.broadcast
val result = bigDF.join(broadcast(smallDF), 'id')
// 调整 broadcast 阈值
spark.conf.set('spark.sql.autoBroadcastJoinThreshold', '209715200') // 200MB
# 方案三:分离热点 Key 单独处理
val hotKeys = Seq('null', 'unknown', '')
val normalDF = df.filter(!col('key').isin(hotKeys: _*))
val hotDF = df.filter(col('key').isin(hotKeys: _*))
// hotDF 单独处理后 union
3.3 OOM 问题系统性排查
场景: Executor OOM 被 Kill / Driver OOM / Container 被 YARN 强制终止
|
OOM 类型 |
日志特征 |
解决方案 |
|---|---|---|
|
Executor Java Heap OOM |
java.lang.OutOfMemoryError: Java heap space |
增大 --executor-memory;减少数据 cache;检查是否有大对象 |
|
Executor 堆外内存溢出 |
Container killed by YARN for exceeding memory limits |
增大 spark.executor.memoryOverhead(至少512m,建议 executor-memory×20%) |
|
Driver OOM |
java.lang.OutOfMemoryError in Driver |
增大 --driver-memory;避免 collect() 大数据集到 Driver |
|
GC Overhead |
GC overhead limit exceeded |
开启G1GC:-XX:+UseG1GC;减少对象创建;开启 Kryo 序列化 |
|
Shuffle OOM |
spark.shuffle.* 相关 OOM |
增大 spark.shuffle.memoryFraction;减少 shuffle 数据量 |
# 开启详细 GC 日志(排查 GC 问题)
--conf 'spark.executor.extraJavaOptions=-XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps'
3.4 Spark 作业监控“三板斧”
场景: 如何快速判断一个 Spark 作业的性能瓶颈在哪里
① Spark Web UI(4040 / History Server 18080)关键页面:
- Jobs 页:查看 Failed / Running Job,看总耗时分布
- Stages 页:重点看 Shuffle Read/Write Size(大说明数据量多,考虑优化 Join)
- Executors 页:看各 Executor GC Time(> 5% 说明 GC 严重)和 Task Time 是否均匀
- SQL 页(Spark SQL):查看物理执行计划,找 SortMergeJoin(可优化为 BroadcastHashJoin)
② 日志快速查看
yarn logs -applicationId application_xxx -log_files stderr | grep -i 'error\|oom\|killed'
③ 历史作业对比分析
# Spark History Server REST API 查询作业耗时
curl http://history-server:18080/api/v1/applications?limit=20 | python -m json.tool
四、安全运维实战
4.1 Kerberos 日常维护
场景: 作业突然认证失败 / 凌晨定时任务认证过期
注意: 长时间 Spark 作业(> Kerberos Ticket 有效期)必须配置 keytab 自动续票,否则 Executor 在 Ticket 过期后无法访问 HDFS,作业静默失败
# 检查当前票据状态
klist -e # 查看 TGT 有效期
# 服务账号(headless)使用 keytab 认证(生产定时任务标准写法)
kinit -kt /etc/security/keytabs/hdfs.keytab hdfs/$(hostname -f)@REALM.COM
# Spark 作业中内嵌认证(长时间运行作业)
spark-submit \
--conf spark.yarn.keytab=/etc/security/keytabs/spark.keytab \
--conf spark.yarn.principal=spark/host@REALM.COM \
myapp.jar
# 强制续票(Ticket 快过期时)
kinit -R # 续票(需 renewable 有效期内)
4.2 HDFS 权限快速配置
场景: 新业务组入驻,需要创建目录并授权,多用户共享数据
最佳实践: 对敏感数据目录启用加密 Zone:hdfs crypto -createZone -keyName prod_key -path /warehouse/pii,数据静态加密,对上层应用透明
# 创建业务目录,设置组权限
hdfs dfs -mkdir -p /warehouse/team_a
hdfs dfs -chown -R hdfs:team_a /warehouse/team_a
hdfs dfs -chmod 775 /warehouse/team_a # 组内可写,其他只读
# 使用 ACL 精细化授权(组无权限时追加特定用户)
hdfs dfs -setfacl -m user:alice:rwx /warehouse/team_a
hdfs dfs -setfacl -m user:bob:r-x /warehouse/team_a
hdfs dfs -getfacl /warehouse/team_a # 验证 ACL
# 设置目录配额,防止单业务占满空间
hdfs dfsadmin -setSpaceQuota 5t /warehouse/team_a # 限制5TB
hdfs dfsadmin -setQuota 1000000 /warehouse/team_a # 限制100万文件
五、数据管道运维实战
5.1 DistCp 集群间数据迁移
场景: 跨机房/集群迁移数据,或做数据备份
注意: 大规模迁移(TB级)必须设 -bandwidth 限速,否则会占满 DataNode 所有带宽,影响生产读写。推荐在业务低谷(凌晨2-6点)执行
# 基础迁移
hadoop distcp hdfs://src-cluster:8020/data/orders hdfs://dst-cluster:8020/data/orders
# 增量同步(只同步新增/修改文件)
hadoop distcp -update hdfs://src/data hdfs://dst/data
# 限速迁移(避免占满网络,单位 MB/s)
hadoop distcp -bandwidth 100 -m 20 hdfs://src/data hdfs://dst/data
# 保留文件权限/所有者/时间戳
hadoop distcp -pbugpt hdfs://src/data hdfs://dst/data
六、故障排查决策树
◈ 作业失败:首先看 YARN Web UI(8088) → application detail → 失败 Container 日志
◈ HDFS 写入失败:hdfs dfsadmin -report 看 DataNode 状态 → 看 NameNode 日志 → 检查磁盘
◈ 集群变慢:先 top 看 CPU/内存 → iostat 看 I/O → 再看 YARN 队列是否满负荷
◈ 认证失败:klist 检查票据 → kinit 重新认证 → 检查 KDC 服务状态
◈ 调度作业不触发:检查 Oozie 服务状态 → 检查 Coordinator 时区配置 → 检查输入数据是否就绪

浙公网安备 33010602011771号