大数据 SQL 数据倾斜与数据膨胀的优化与经验总结
本文参考多篇有关大数据的数据倾斜的解决思路,总结作为工作参考使用,引用自 1,大数据 SQL 数据倾斜与数据膨胀的优化与经验总结 2,Hive SQL 优化(解决数据倾斜)
问题描述
数据倾斜
数据倾斜是指在分布式计算时,大量相同的key被分发到同一个reduce节点中。针对某个key值的数据量比较多,会导致该节点的任务数据量远大于其他节点的平均数据量,运行时间远高于其他节点的平均运行时间,拖累了整体SQL 执行时间。其主要原因是key值分布不均导致的Reduce处理数据不均匀。本文将从Map端优化,Reduce端优化和Join端优化三方面给出相应解决方案。
数据膨胀
数据膨胀是指任务的输出条数/数据量级比输入条数/数据量级大很多,如100M的数据作为任务输入,最后输出1T的数据。这种情况不仅运行效率会降低,部分任务节点在运行key值量级过大时,有可能发生资源不足或失败情况。
排查定位篇(重要)
本节主要关注于业务SQL本身引起的长时间运行或者失败,对于集群资源情况,平台故障本身暂不考虑在内。
1.首先检查输入数据量级。与其他天相比有无明显量级变化,是否因为数据量级的问题天然引起任务运行时间过长,如双11,双十二等大促节点。
2.观察执行任务拆分后各个阶段运行时间。与其他天相比有无明显量级变化;在整个执行任务中时间耗时占比情况。
3.最耗时阶段中,观察各个Task的运行情况。Task列表中,观察是否存在某几个Task实例耗时明显比平均耗时更长,是否存在某几个Task实例处理输入/输出数据量级比平均数据量级消费产出更多。
4.根据步骤3中定位代码行数,定位问题业务处理逻辑。
优化篇
(1)数据倾斜
1,Map端优化
1.1 读取数据合并
在数据源读取查询时,动态分区数过多可能造成小文件数过多,每个小文件至少都会作为一个块启动一个Map任务来完成。对于文件数量而言,等于 map数量 * 分区数。对于一个Map任务而言,其初始化的时间可能远远大于逻辑处理时间,因此通过调整Map参数把小文件合并成大文件进行处理,避免造成很大的资源浪费。
1.2 列裁剪
减少使用select * from table语句,过多选择无用列会增加数据在集群上传输的IO开销;对于数据选择,需要加上分区过滤条件进行筛选数据。
1.3 谓词下推
在不影响结果的情况下,尽可能将过滤条件表达式靠近数据源位置,使之提前执行。通过在map端过滤减少数据输出,降低集群IO传输,从而提升任务的性能。
1.4 数据重分布
在Map阶段做聚合时,使用随机分布函数distribute by rand(),控制Map端输出结果的分发,即map端如何拆分数据给reduce端(默认hash算法),打乱数据分布,至少不会在Map端发生数据倾斜。
2,Reduce端优化
2.1 增大 reduce 并行度
计算公式:hashCode(key)% reduce 个数
优点:实现十分简单;
缺点:可能缓解数据倾斜,不一定有效果
2.3 排序优化
Order by为全局排序,当表数据量过大时,性能可能会出现瓶颈;
Sort by为局部排序,确保Reduce任务内结果有序,全局排序不保证;
Distribute by按照指定字段进行Hash分片,把数据划分到不同的Reducer中;
CLUSTER BY:根据指定的字段进行分桶,并在桶内进行排序,可以认为cluster by是distribute by+sort by。
对于排序而言,尝试用distribute by+sort by确保reduce中结果有序,最后在全局有序。
-- 原始脚本
select *
from user_pay_table
where dt = '20221015'
order by amt
limit 500
;
-- 改进脚本
SELECT *
FROM user_pay_table
WHERE dt = '20221015'
DISTRIBUTE BY ( CASE
WHEN amt < 100 THEN 0
WHEN amt >= 100 AND age <= 2000 THEN 1
ELSE 2
END )
SORT BY amt
LIMIT 500
;