环境
cdh 6.3.2-1.cdh6.3.2.p0.1605554
hive 2.1.1-cdh6.3.2 rb3393cf499504df1d2a12d34b4285e5d0c02be11
问题
有些dw宽表加工速度慢
表加工逻辑是io密集任务,不是cpu计算任务,且不涉及数量特别多表关联
过程
看了8088,发现倾斜基本发生在mapstage
看DAG调度图现象就是只分配了极少个数的map数量
spark在map阶段的分配map个数的底层原理有学习过但是本人不才没有学好.... :<
不过map看个数是 根据上游ods的文件块大小和个数来分配的,只分配很少
(dw层表默认序列化反序列化的类是 orc,blocksize也是默认的,所以不涉及可不可切分等问题)
思路1
ods文件块大小有问题的原因是 用的抽数工具是flinkx或者datax,没有调教好合适参数,导致分区内和oracle的文件保持一致,出现了不均匀或者大文件
也有可能是抽数过来以后中间件做过小文件合并导致有大文件
调整参数应该是一个很好的办法,但是我们是生产环境...所以不太好控制
所以这个思路保留~
思路2(重要)
如果无法从ods表处做处理(类似hive etl的时候处理)
那就考虑在加工的时候,也就是说在application创建,也就是在会话级别调优这个作业达到目的
总结一下两个思路就是 针对map缓慢的作业,提前etl好 依赖表 ,或者就是在读的时候控制
gpt给出的参数
set hive.merge.size.per.task=16000000 ;
--mergefile作业的时候每个task处理的数据量
--默认256
set mapred.max.split.size=8000000 ;
-- mapreduce系列的参数设置,但是spark也有用
-- 切文件的大小参数的设置
--默认256
set hive.exec.orc.default.block.size=32000000 ;
-- orc文件的导入导出的参数配置
具体操作(重要)
set hiveexec.reducers.bytes.per.reducer;
-- 这个参数指定了每个Reducer理的输入数据量的上限(以字节为单位)。如果作业的输入数据量超过了这个阈值,Hive会自动增加Reducer的数量,以保证每个Reducer处理的数据量不超过该阈值。这个参数的默认值是1GB。
set hive.merge.smallfiles.avgsize;
--这个参数用于控制Hive在执行文件并操作时的平均文件大小(以字节为单位)。当Hive执行文件合并操作时,它会尝试将多个小文件合并为一个或少量的大文件,以提高查询性能。该参数的默认值是256MB。
set hive.merge.size.per.task;
--这个参数指定了每个任务(Task)执行文件合并操作时的最大输入数据大小(以字节为单位)。如果一个任务的输入数据大小超过了这个阈值,Hive会将该任务的输出结果拆分为多个文件并进行合并。该参数的默认值是256MB。
set hive.exec.orc.default.block.size:
--设置ORC文件的默认块大小。假设有一个大型数据集,每个ORC文件默认的块大小为256MB。如果想要优化查询性能,可以将块大小调整为128MB,以减少每次查询读取的数据量。
--对于一般的 union
--元数据库里的结果是不对的,要手动加表分析 或 增加reduce阶段的操作 distribute by
--有个小知识点,就是unionall+limit的时候可能会有bug
-- unionall+ 四个by的时候是不需要注意这个的,因为四个by都是对结果集处理的
-- 常用 distribute by rand() 随机分配
insert overwrite table tb3 partition (day='${YYYYMMDD}')
select col1 , col2 from tb1 where day='20230101'
union all
select col1 ,col2 from tb2 where day='20230101'
distribute by col1
-- 普通的sql 也可以执行
insert overwrite table tb3 partition (day='${YYYYMMDD}')
select col1 , col2 from tb1
join tb2 on tb1.col1 = tb2.col1
where tb11.day='20230101'
distribute by rand()
-- 处理表
drop table tb3;
set hive.merge.size.per.task=64000000;
create table tb3 as
select * from dw.xxxxxxxxxxxxxxxx where day='20230722'
distribute by col;
--结果集
[node1]$ hdfs dfs -ls -h hdfs://马赛克/user/hive/warehouse/马赛克
Found 18 items
-rwxrwxrwx 3 bdp supergroup 62.4 M 2023-07-24 15:21 hdfs://马赛克/user/hive/warehouse/马赛克/000000_0
-rwxrwxrwx 3 bdp supergroup 62.4 M 2023-07-24 15:21 hdfs://马赛克/user/hive/warehouse/马赛克/000001_0
-rwxrwxrwx 3 bdp supergroup 62.4 M 2023-07-24 15:21 hdfs://马赛克/user/hive/warehouse/马赛克/000002_0
-rwxrwxrwx 3 bdp supergroup 62.4 M 2023-07-24 15:21 hdfs://马赛克/user/hive/warehouse/马赛克/000003_0
-rwxrwxrwx 3 bdp supergroup 62.4 M 2023-07-24 15:21 hdfs://马赛克/user/hive/warehouse/马赛克/000004_0
初步结论
就算是动态分配的spark服务跑hql也是可以做结果集的分片的
spark executor 和 map 数的关系
作业显示是65map和17executor的关系, 好像是1:4
有大佬和我讲解过原理,但我还是没记住.... : < 跟容器有关
思路3(扩展)
刚才设置的参数是64m左右一个,但是场景看起来并不是通用的
所以这个问题如果想要延时下去继续研究
其实就是要掌握这些map reduce参数 或者split或者分区参数应该设置的多大比较合适
比如分区表A的分区a内有2个文件块
大小分别是300 400
实际hive 用spark mr的时候会自动切割,默认256一个
那么就会产生3个map
3个map那跑的特别慢比如说跑了80分钟,或者平均时间都很长,不满意
那这个时候,如果按照刚才的split参数设置 ,切32一个
256/32= 8倍
那么就是80分钟/8 = 10分钟,理想效果是如此
不过这么做会非常消耗资源
其他自用的参数
set hive.execution.engine=spark;
set hive.execution.engine=mr;
--有时候spark跑不了的任务可以走mr跑,但是注意集群资源
set hive.spark.client.future.timeout=200;
set hive.spark.client.connect.timeout=80000ms;
--显而易见的参数
set spark.driver.memory=10.8g
set spark.yarn.driver.memoryOverhead=1.2g
-- driver 12g
set spark.executor.memory=8.55g;
set spark.yarn.executor.memoryOverhead=1.51g
-- executor 10g
set hive.exec.reducers.bytes.per.reducer=64000000;
--控制reduce大小
set hive.merge.smallfiles.avgsize=16777216; --16m
--合并小文件
set spark.dynamicAllocation.cachedExecutorIdleTimeout
set spark.dynamicAllocation.maxExecutors ;
set spark.dynamicAllocation.minExecutors ;
set spark.dynamicAllocation.executorIdleTimeout ;
set hive.exec.orc.split.strategy;
-- 下面的试着没什么用的样子