订阅更新

100TB的Hive表跑了6小时——大规模数据处理的调优思路

Hadoop手册 第 11 题 约 9 分钟读完

本文目录
  1. 先说结论
  2. 调优方向一:输入优化(效果最大)
  3. 调优方向二:计算优化
  4. 调优方向三:Shuffle优化
  5. 调优方向四:资源优化
  6. 实战经验:100TB报表从6小时到40分钟
  7. 调优的系统方法论——排查清单
  8. 面试高频追问
  9. 总结

先说结论

大规模Hive/Spark作业调优有五个方向:① 输入优化(分区裁剪、列裁剪、谓词下推);② 计算优化(Reduce数量、并行度、MapJoin);③ Shuffle优化(压缩、Combiner、减少数据量);④ 输出优化(合并小文件、合理文件格式);⑤ 资源优化(Executor配置、动态分配)。按ROI排序:输入优化效果最大,其次是Shuffle优化。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

在某知名出海硬件品牌用EMR时,有一张设备激活明细表,每天新增约30GB,历史累计超过100TB。年底要跑一个全量报表——按国家、设备型号、月份维度统计激活量和复购率。第一次跑花了6个多小时,迟迟出不来。后来通过一系列调优把时间压到了40分钟。大规模数据处理调优是面试高频题,面试官想看你有没有系统性的调优方法论。

调优方向一:输入优化(效果最大)

-- 错误写法:没有分区裁剪,扫描100TB全量数据
SELECT country, device_model, month,
       COUNT(DISTINCT device_id) AS activations
FROM device_activations
GROUP BY country, device_model, month;
 
-- 正确写法:加分区条件,只扫描需要的年份
SELECT country, device_model,
       DATE_FORMAT(activation_time, 'yyyy-MM') AS month,
       COUNT(DISTINCT device_id) AS activations
FROM device_activations
WHERE dt BETWEEN '2023-01-01' AND '2023-12-31'  -- 只扫描1年
GROUP BY country, device_model,
         DATE_FORMAT(activation_time, 'yyyy-MM');
 
-- 效果:从扫描100TB降到扫描约30TB
-- 输入减少70%,执行时间从6小时降到2小时
 
-- 列裁剪:不要SELECT *
-- 原表有50个字段,只需要5个
-- Parquet/ORC格式的列裁剪效果极好
-- 只读5列 vs 读50列:IO减少90%

分区裁剪+列裁剪是调优ROI最高的手段:很多人一上来就调Executor内存、Shuffle参数,其实最有效的是先看SQL——有没有加分区条件?有没有SELECT *?这两个问题解决了,大部分慢查询都能快很多。

调优方向二:计算优化

-- Reduce数量调优
-- 太少:单个Reduce数据量大,处理慢
-- 太多:启动开销大,产生大量小文件
SET hive.exec.reducers.bytes.per.reducer = 256000000;  -- 256MB/Reduce
 
-- MapJoin优化(小表广播)
SET hive.auto.convert.join = true;
SET hive.mapjoin.smalltable.filesize = 25000000;  -- 25MB以下自动MapJoin
-- 在Spark里类似:
-- spark.sql.autoBroadcastJoinThreshold = 209715200  -- 200MB
-- 我在出海硬件品牌把这个值从10MB调到200MB
-- JOIN自动变Broadcast,作业时间减少40%
 
-- AQE(Adaptive Query Execution,Spark 3.0+)
SET spark.sql.adaptive.enabled = true;
-- AQE在运行时自动:
-- (1) 合并过小的Shuffle Partition
-- (2) 自动转换Sort Merge Join为Broadcast Join
-- (3) 自动处理数据倾斜

调优方向三:Shuffle优化

优化方法配置/写法效果
列裁剪SELECT需要的列,不用*Shuffle数据量减少30-50%
过滤前置WHERE条件在JOIN之前执行减少参与Shuffle的数据量
Shuffle压缩spark.shuffle.compress = true网络传输量减少50%+
CombinerHive自动使用,Spark reduceByKey本地预聚合减少传输
合理Partition数spark.sql.shuffle.partitions = 200避免太多或太少

调优方向四:资源优化

# Spark作业的资源配置经验
 
# Executor数量和核数
# 经验:总核数 = 集群可用核数 × 70%(留30%给OS和其他作业)
# 每个Executor 4-5核最优(太多会有GC和锁竞争)
--num-executors 40
--executor-cores 4
 
# Executor内存
# 经验:每核2-4GB,外加20%的overhead
--executor-memory 12g
--conf spark.executor.memoryOverhead=2g
 
# Driver内存(如果有collect等操作需要调大)
--driver-memory 8g
 
# 动态分配(推荐开启)
--conf spark.dynamicAllocation.enabled=true
--conf spark.dynamicAllocation.minExecutors=5
--conf spark.dynamicAllocation.maxExecutors=100
# 根据实际负载自动调整Executor数量

实战经验:100TB报表从6小时到40分钟

在某知名出海硬件品牌,那个6小时的全量报表的优化过程:

第一步:分区裁剪。加上WHERE dt条件只扫描2023年数据(约30TB)。6小时降到2小时。

第二步:列裁剪。原表50列只需要5列,Parquet列式存储只读需要的列。2小时降到50分钟。

第三步:MapJoin优化。JOIN的维度表(设备型号表)只有10MB,调大autoBroadcastJoinThreshold后自动变成Broadcast Join。50分钟降到40分钟。

第四步:AQE。开启Spark的AQE,自动合并小Partition、处理轻微的数据倾斜。没有显著缩短时间但稳定性提升了(之前偶尔因为倾斜跑90分钟)。

最终效果:6小时降到40分钟,提升9倍。其中分区裁剪贡献66%(4小时),列裁剪贡献27%(1小时10分钟),MapJoin贡献7%。再次验证:输入优化的ROI远大于其他调优方向。

调优的系统方法论——排查清单

检查项怎么查预期效果
有没有分区裁剪?EXPLAIN看Partition数减少50-90%输入
有没有SELECT *?看SQL减少30-50%IO
JOIN策略对不对?EXPLAIN看Join类型Broadcast比Shuffle快10倍
Shuffle数据量大不大?Spark UI看Shuffle Read/Write压缩+列裁剪减少50%
有没有数据倾斜?Spark UI看Task耗时分布AQE或加盐打散
Executor配置合理吗?看资源使用率避免OOM或资源浪费
输出小文件多不多?看输出文件数coalesce合并

面试高频追问

追问一:Spark作业OOM了怎么排查?

分两种情况:① Driver OOM——通常是collect/count触发了全量数据拉取到Driver,或者广播变量太大。调大driver-memory或优化逻辑。② Executor OOM——通常是数据倾斜(某个Partition太大)或JOIN膨胀。用Spark UI看每个Task的内存使用,找到最大的Partition定位原因。

追问二:怎么判断调优的优先级?

先看Spark UI的时间分布:① 大部分时间在Scan(输入阶段)则优化输入(分区/列裁剪);② 大部分时间在Shuffle则优化Shuffle(减少数据量/压缩);③ 某个Task特别慢则排查数据倾斜;④ 等资源时间长则调整YARN队列/Executor配置。按时间占比排优先级。

追问三:调优到极限还是慢怎么办?

三个方向:① 加资源(加Executor/加节点)——最直接但成本高;② 改架构——把实时需求从离线批处理改成增量处理(比如Delta Lake的MERGE);③ 预计算——把频繁查询的结果提前算好存DWS层,查询时直接读预计算结果。我在出海硬件品牌最终选的是把部分报表改成增量更新,执行时间从40分钟降到5分钟。

总结

大规模数据调优面试讲五个方向按ROI排序:① 输入优化(分区裁剪+列裁剪,效果最大);② Shuffle优化(减少数据量+压缩);③ 计算优化(MapJoin+AQE+Reduce数量);④ 资源优化(Executor配置+动态分配);⑤ 输出优化(合并小文件)。系统性的调优方法论比单一技巧更重要——先看Spark UI找瓶颈,再针对性优化。能讲出100TB报表从6小时到40分钟的完整过程和每步效果,面试官会非常满意。

下一篇聊一个现实的问题:EMR集群每月账单好几万美元——云上Hadoop怎么省钱?

你们做过什么Hive/Spark调优?最大的优化效果是什么?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器