1 前言
基于Spark 2.3.0测试笔记一:Shuffle到胃疼的初步测试结论,由于未经声明的参数行为变化, 2.3.0的性能对比惨到不行。本轮测试在之前的基础上对2.3.0加上额外的参数设置spark.sql.statistics.fallBackToHdfs true
进行新一轮的性能测试,以期望令人满意的结果。
2 测试数据
benchmark | scale | fileformat | partitioned | link |
---|---|---|---|---|
TPCDS | 1T | parquet | true | https://github.com/yaooqinn/tpcds-for-spark |
3 实验对象
3.1 参照组
baseline | modified | commit | link |
---|---|---|---|
2.1.2 | true | 9ef23ae | https://github.com/yaooqinn/spark/tree/v2.1.2-based |
3.2 实验组
baseline | modified | commit | link |
---|---|---|---|
2.3.0 | false | 992447f | https://github.com/yaooqinn/spark/tree/v2.3.0-based |
4 配置
4.1 硬件配置
机器类别 | CPU | Memory | Disk | 台数 | Services |
---|---|---|---|---|---|
虚拟机 | 4 × 1 × 1 | 32g | 500g × 1 | 5 | NN(1) SNN (1) RM(1) HMS(1) SHS(1) |
物理机 | 48 × 2 × 12 | 256g | 7.3T × 12 | 3 | DN(3) NM(3) |
物理机 | 48 × 2× 12 | 256g | 1.1T × 1 | 4 | DN(4) NM(4) |
物理机 | 32 × 2 × 8 | 128g | 3.6T × 12 | 1 | DN(1) NM(1) |
物理机 | 40 × 2 × 10 | 256g | 500g × 1 | 1 | NM(1) |
物理机 | 48 × 2 × 12 | 32g | 1.1T × 1 | 1 | DN(1) |
4.2 metrics
4.3 SparkConf
## Basic Settings ##
spark.master yarn
spark.submit.deployMode client
spark.serializer org.apache.spark.serializer.KryoSerializer
spark.kryoserializer.buffer.max 256m
spark.local.dir ./local
## Hadoop Settings ##
spark.hadoop.fs.hdfs.impl.disable.cache true
spark.hadoop.fs.file.impl.disable.cache true
## Driver/AM Settings ##
spark.yarn.am.cores 2
spark.yarn.am.memory 2g
spark.yarn.am.memoryOverhead 512
spark.yarn.am.extraJavaOptions -XX:PermSize=1024m -XX:MaxPermSize=2048m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
spark.driver.maxResultSize 2g
spark.driver.memory 30g
spark.driver.extraJavaOptions -XX:PermSize=1024m -XX:MaxPermSize=1024m
## Executor Settings ##
spark.executor.instances 40
spark.executor.cores 4
spark.executor.memory 20g
spark.executor.memoryOverhead 4096
spark.executor.extraJavaOptions -XX:PermSize=1024m -XX:MaxPermSize=1024m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
## Security Settings ##
spark.yarn.keytab ?
spark.yarn.principal ?
## Dynamic Allocation Settings ##
spark.shuffle.service.enabled true
spark.dynamicAllocation.enabled false
spark.dynamicAllocation.initialExecutors 1
spark.dynamicAllocation.minExecutors 1
spark.dynamicAllocation.maxExecutors 50
## SQL Configurations ##
spark.sql.autoBroadcastJoinThreshold 204857600
spark.sql.warehouse.dir /user/spark/warehouse
# spark.sql.hive.convertCTAS true
# spark.sql.sources.default parquet
spark.sql.shuffle.partitions 1024
# spark.sql.hive.convertMetastoreParquet false
spark.sql.crossJoin.enabled=true
## History Server Client Settings ##
# spark.eventLog.enabled true
spark.eventLog.compress true
spark.eventLog.dir hdfs:///spark2-history/
spark.yarn.historyServer.address ?:18081
spark 2.3.0加上该配置
spark.sql.statistics.fallBackToHdfs true
5 测试结果
5.1 实验数据
- 列1:sql statement
- 列2:参照组结果
- 列3:实验组结果
- 显示规则见上图
5.2 定性结果
- query19在参照组下没跑出结果,失误,没记下log。
- query 77 两组皆未出结果,
spark.driver.maxResultSize 2g
设置太小 - 测试只run了一轮,所以结果并不是十分严谨,[-0.1, 0.1]之间,就认为性能相当
- 可以看到本轮测试,实验组的性能相比前一轮测试有大幅度的提升,说明诸多SQL都由SortMerge转成了Broadcast
- 但是总体上而言,刨去“小查询”,依然有Query 9 72 88 等感受到了明显的下降。
- query 72 怎么又有你?还能不能玩了?
- 性能提升是应该的,性能下降就打脸了。
6 相关分析
6.1 执行计划
上图显示实验组在加上fallback参数后,逻辑计划除了长相不一样,但逻辑结构上已经一致了。
6.2 Job Metics对比
- 两轮Applications的所有Job没有task失败的记录运行良好
- Job Id 11是两者性能的分水岭
6.3 Stage Metrics
- 参照组的13、实验组的14,实为同一个Stage,主要的时差在此
- 各项参数基本一致或者完全一致,除了Duration这一下,实验组完完全全的落后
- 比较两者的DAG完全一致,逻辑上没问题,问题的原因就可能是对应的物理算子,或者Spark Core的改动产生的性能regression了。或者是我维护的分支不小心加了性能优化特性[吃了一惊的表情]
6.4 Task Metrics
- 运气不错 Task ID 5619正巧排序后都在第一位,可以看到性能问题真正就是在task的执行过程慢,也基本印证上面6.3(3)的推断
6.5 日志分析
- 截取5619从开始到结束段的executor日志进行对比
- 执行节点恰好一致
- 与之并行的相关task也一致的调度与该节点
- shuffle service的server也一致
- 图中红框处,参照组Executor出现1分钟左右间隔,而实验组Executor出现3分钟左右的间隔,这时段基本可以理解为task正在吭哧吭哧的执行。
6.6 执行计划 VS DAG
- 对比执行计划 Stage14 为最后一个SortMergeJoin的右表,对应我们Stage 13就是在做Sort的左表(中间表)
- 所以基本可以猜测
SortExec
在2.3.0有性能regression,由于跨过了2.2相关的版本,所以并不能确定引入的时间点。
7 总结
- 对于那些没有Hive Statistics和Spark Statistics信息的表,需要注意在2.3.0之后
spark.sql.statistics.fallBackToHdfs true
去fallback,当然最好还是能去执行analyze来生成。 -
SortExec
物理算子应该极有可能有性能regression,需要看代码/PR的变更。后续有时间可以再带点分享。有兴趣的可以根据本文提供的线索去分析一下,如果是的话可以贡献社区。
8 后记
蜀道难,还能不能玩了?