sparksql优化之路

最近一直由于公司一个重要的作业,从Tez切换到sparksql,需要对sparksql进行优化。这个表都是left join,慢就慢在join阶段

Tez之前根据优化参数,执行时间在7分钟到12分钟之间浮动,sparksql进行一些参数优化,一直在17到24分钟浮动,效率太低。最后查看sparksql的执行时的shuffle阶段发现,每个表参与的shuffle数据量相差很大,最大的612GB,最小的2.7GB,然而2.7GB的表却不能进行广播,内存也不可能那么大,我们配置的是200M表进行广播。最后根据shuffle表的数据大小调整join顺序,把最小的表放在最前面join,最大的表放在最后join,性能立即提升50%,直接到10分钟左右。下面针对一些优化中使用的参数进行说明:

设置动态资源分配

spark.dynamicAllocation.enabled  是否开启动态资源配置,根据工作负载来衡量是否应该增加或减少executor,默认false
spark.shuffle.service.enabled  启用外部随机shuffle服务。此服务保留执行者编写的无序处理文件,以便安全地删除执行者spark.dynamicAllocation.enabled设置为true了,必须设置这个参数也为true,默认是false
spark.dynamicAllocation.executorIdleTimeout  当某个executor空闲超过这个设定值,就会被kill,默认60s
spark.dynamicAllocation.schedulerBacklogTimeout  这个参数的默认值是1秒,即当任务调度延迟超过1秒的时候,会请求增加executor,而且是指数形式的请求
spark.dynamicAllocation.maxExecutors  动态分配最大executor个数,默认infinity
spark.dynamicAllocation.initialExecutors  动态分配初始executor个数默认值=spark.dynamicAllocation.minExecutors
spark.dynamicAllocation.cachedExecutorIdleTimeout  当某个缓存数据的executor空闲时间超过这个设定值,就会被kill,默认infinity

spark.executor.memory 设置每个executor多少内存
spark.executor.cores   设置每个executor的cpu数量

spark.executor.memoryOverhead  设置executor申请堆外内存大小,默认是executor的10%
spark.memory.fraction                                   0.7
spark.shuffle.file.buffer  设置shuffle时的buffer大小默认是32k
spark.memory.offHeap.enabled  是否可以设置堆外内存,默认是false
spark.memory.offHeap.size  申请堆外内存大小,他的设置不会影响堆内存大小,但是会受机器的整个内存大小影响,这个不能设置太大,我这测试1024mb这个值刚好
spark.sql.autoBroadcastJoinThreshold  根据表大小是否进行广播,默认10M,测试发现按照分区获取数据,小于10M,仍然不会进行广播,所以设置稍晚大点,我们的是209715200(200M)
spark.sql.statistics.fallBackToHdfs 广播时是否下推到hdfs获取数据大小,默认是false,false时广播时是从metastore获取的大小

spark.sql.join.preferSortMergeJoin 开启尝试使用hash join的开关,默认是false,使用的是sort merge join,当前SparkSQL支持三种Join算法:shuffle hash join、broadcast hash join以及sort merge join
spark.reducer.maxSizeInFlight 该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据,默认是48m
spark.sql.inMemoryColumnarStorage.batchSize  默认值是10000
spark.sql.orc.filterPushdown 默认值是false

之前一直增加executor的数量和cpu,但是执行性能没有提升,查看sparksql页面发现task的并行度没有上去,默认并行度是200,sparksql需要同时设置以下两个参数才生效,设置为executor数量*cpu核数的2~3倍

spark.sql.shuffle.partitions=2700   (默认值200)并行度太低就没有充分利用cpu和executor
spark.default.parallelism=2700

以下是我们线查看每个表shuffle时数据量的大小,A表是主表,然后按顺序left join后面的所有表,我们这个join没有数据倾斜,这个对相关参数进行优化后执行一直维持17~24分钟

db1.T_IFS_PS_CUSTS_ATTRIB A 61.5G
db1.T_IFS_CUSTS_ATTR_F B 70.4GB
db2.FS_CUSTS_LEVEL C 42.3GB
db2.FS_CUSTS_BAL_SUM D 612GB
db2.FS_CUSTS_PRD_TRADE_VALUE E 38.3GB 
db2.FS_CUSTS_BAL_SUM F 10.7GB
db2.FS_ORANGE_TRADE_SUM H 2.7GB 
tmp_FS_CUSTS_PROD_FLAG I 38.3GB 
db3.B_IFS_CUSTS_CARD_LEVEL_INFO J 5.8GB
db2.FS_CUSTS_BAL_SUM K 7.6GB
db2.FS_CUSTS_ASSET_LEVEL_M L 7.5GB
db2.FS_CUSTS_YH_ASSET_LEVEL_M M  13.1GB
db2.FS_CUSTS_BAL_SUM_HIS N  16.8GB 
db2.FS_DF_CUSTS_TRANS_SUM O 7.5GB

后来直接把db2.F_CUST_BAL_SUM这个大表放到最后进行join,直接10分钟就执行完成了。为什么调整顺序之后就提升了50%性能,我的理解是这个放到最后执行,就不会一直参与计算,之后最后才进行参与计算,耗费的资源就很少。没有调整顺序时最短的task执行1.4min,最长的5.7min,浮动很大,调整顺序后最短的1min,最长的2.4min。

sparksql优化在路上,还需继续努力研究原理。

你可能感兴趣的:(Spark)