1. 起因
日常大数据的处理,常见的数据输出就是最大最小值,求个和,求个平均数这种,常见的写法,写个hql,先分个组,再加一个max或sum就可以
SELECT id,name,
max(score1),
sum(score2),
avg(score3)
FROM table
GROUP BY id,name
当然如果条件更复杂一些,比如加一个if判断,就是sql稍微长一些,但还是能写出来
本地测试,还OK,测试环境,勉强能行,感觉不错,无非就是怼资源的问题
但放到上产上,直接傻眼
snappy压缩,原始数据500G
280亿条数据
第一步Shuffle Write 800G
接下来的任务预估需要8个小时跑完
我可是用1.5T的内存,200个并发,内存经常溢出,超时,GC时间巨长
2.优化开始
sql有问题,首先肯定第一反应就是优化资源分配和使用
--conf spark.storage.memoryFraction=0.7
有很多任务心跳超时
--conf spark.executor.heartbeatInterval=240
任务序列化时间过长
--conf spark.locality.wait=60
发现GC时间过长,优化jvm参数
-XX:+UseG1GC
发现spark有任务合并,在特殊位置增加reparation,强制任务分隔
dataset.repartition(20000)
经过一系列优化发现有效果,但收效甚微,最后一步执行还是要以小时计算
仔细分析了一下sql,是不是spark底层对多次的max,min这种,在数据量大的时候需要多次遍历数据
3. 问题解决
最后的决定,用代码写,再试一次
Dataset<Row> ds = spark.sql(sql);
dsTag0200.javaRDD().mapPartitionsToPair(
数据转型
分组当key做成tuple2
此处我缓存了一些需要后面聚合的差值
).reduceByKey(
判断最大最小
sum的聚合操作使用差值直接聚合
一遍就可以直接输出最终结果
)
激动的心颤抖的手,任务执行,下班走人,生死有命富贵在天,执行结果,大宝明天见
当然最终结果1个半小时结束,效率还可以接受而且这样内存比较受控,可以更高的增加executor等通过合理资源去提高并行度
4 总结
对于hql相对复杂的一些操作,尤其是对原始数据,一定要考虑数据量的问题,数据量大到一定程度,不是怼资源可以过去的了,而且这样优化的空间也会变得很少