tpcds和ycsb是业界衡量性能的测试基准,为技术选型做一些参考,同时也可以通过它来做调优基准,其中包含大数据领域。本文介绍是利用tpcds和ycsb测试结果调优spark sql和hbase读写性能。
这次性能调优的集群规模:
1台master机器:24核,10块2T硬盘,千兆网卡,128G。
31台slave机器:24核,10块2T硬盘,千兆网卡,64G。
集群部署规划:
master机器安装Namenode,Resourcemanager,HiveServer,HbaseMaster,spark客户端。
所有slave机器包括master安装datanode,nodemanager,其中20台slave机器安装regionserver,10台slave机器安装hbase client。
tpcds
tpcds包括7张事实表,17张纬度表。测试集包含对大数据集的统计、报表生成、联机查询、数据挖掘等复杂应用,测试用的数据和值是有倾斜的,与真实数据一致。
tpcds sql脚本下载地址:https://github.com/julianhyde/tpcds
hive数据生成脚本下载地址:https://github.com/hortonworks/hive-testbench。
这次tpcds性能我们针对的是spark 2.1.1,spark的部署模式为spark-on-yarn,主要针对query47,query53,query71,query84,query63,query99,query89,query79,query19 10个用例。
数据准备
生成数据分为三部分:
1. 通过hive-testbench脚本生成30T原始数据
2. 创建hive外表关联数据
3. 将数据转换为orc数据格式。
生成的30T数据在hdfs显示27T,但这是正常的,转换程orc格式后,只有6.4T的数据。
为什么选择ORC,Parquet和ORC比较?
压缩率:
性能优化
我们的目标是让10个用例运行时间尽可能少。优化思路其实和其他框架差不多,我们主要会从以下几点出发:
1. 充分利用机器资源
2. 数据:balance,压缩, cache level,传输协议
3. 任务:执行计划,调度算法(数据本地性),rpc:序列化,io传输
4. 框架代码本身优化
机器资源
机器资源主要指的是CPU,内存,网络,磁盘,调整配置参数协调并充分利用它们。
当然,每个集群参数调整并不是绝对的,考虑到不同生产环境应用场景。
这次spark采用的是spark-on-yarn模式,所以我们对hdfs,yarn都要进行相应的优化。以下是我们针对tpcs性能测试给出hdfs和yarn的参考值:
其中:
dfs.datanode.data.dir,yarn.nodemanager.local-dirs,yarn.nodemanager.log-dirs:设置10个盘读写,充分利用磁盘空间和磁盘IO,以便在跑满任务的时候,不会因为磁盘IO导致计算卡住。
yarn.nodemanager.resource.cpu-vcores设置24,与机器核数一样,设置小了利用不上cpu资源,设置大了会导致cpu来回切换任务影响性能。
io.file.buffer.size适当调大,提高吞吐量,使得io读取次数和网络利用达到一个最优比例。
配置nodemanager内存相关项,充分利用好内存资源,比如:map和reduce memory设置为2.5G(内存总大小64G/24核左右)。其他选项配置见nodemanger内存分布图:
数据
- 数据balance
打开balancer,均匀分布数据到集群每个节点, 避免数据集中到某些机器拖慢整体计算。相关参数:dfs.datanode.balance.bandwidthPerSec和
dfs.balancer.blockmovewaittime。dfs.datanode.balance.bandwidthPerSec是限制balance带宽,为了不影响生产环境任务,该值不能太大,且一般避免任务高峰期执行。针对这次性能测试的,我们可以针对性调大快速达到平衡后,再关掉balancer。 - 数据块
默认128M,由于计算文件较大,有的甚至达到几T,默认map数是文件大小/块大小来决定的,设置太小会导致map数太大。对于文件大,集群数量少,建议将block size设置大一些的好。dfs.block.size设置为256M。当然,map数可以通过调大mapreduce.input.fileinputformat.split.minsize来减少map数,具体算法见: - 压缩
生产集群往往会使用lzo和snappy压缩算法,但往往也增加了cpu消耗。如果cpu紧张,网络带宽充足,对于某些用例不用压缩反而性能更好。相关参数有:
mapred.compress.map.output true mapred.map.output.compression.codec LzoCodec mapred.output.compress true mapred.output.compress.codec LzoCodec
执行计划
环境和数据优化后接下来是调优的重点,分析tpcds用例执行过程。从spark-ui日志我们可以看到,整个sql执行时间都是在stage3:
打开stage3的dag和event terminal,主要是在hadoopRDD数据读取,而每个task任务的时间大部分在计算上,其次是红色的task反序列化时间,而task反序列化算法是spark代码写死的,之所以这么长时间是因为这个RDD的task的反序列化时间就要耗费这么长的时间,可能在spark后面的版本这里会得到优化,提供更高效的反序列算法。所以这里主要是分析计算时间为什么怎么长,到底属不属于正常。
我们把问题转向计算的时间,hadoopRdd task主要的工作是在读取hdfs数据块,但是我们从机器上的网络指标上找不到瓶颈点,也就是说,计算的时候网络没有瓶颈。查看cpu和磁盘指标:
cpu指标处于完全利用的状态,但是我们磁盘await却一直有10-20%延迟,查看了磁盘io数据读取,维持在100Mb以下,而我们的磁盘是SAS盘,在150Mb-200Mb之间,照理不应该有这种延迟,查看了系统日志发现磁盘有以下异常:
WARNING: at fs/xfs/xfs_aops.c:1244
参照https://access.redhat.com/solutions/2893711?tour=6 升级了内核包,不再报以上异常,await也降低了,解决后重新跑spark-sql,时间降低了8%左右。
熟悉spark task里面的代码逻辑上的调优,在executor上添加以下参数生成jfr文件分析,因本人能力有限,不熟悉spark代码,这里就不做进一步讨论:
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=filename=executor.jfr,dumponexit=true,settings=profile
除此之外,我们发现cpu资源我们跑满了,但是内存还剩下很多,为了物尽其用,我们调高了spark.shuffle.memoryFraction=0.6 –conf spark.storage.memoryFraction=0.8,默认是spark.shuffle.memoryFraction是0.2,尽然内存足够,那我们就不用考虑在做shuffle或者数据读写的时候超过executor一定比例内存写到磁盘。提高性能5%。
partions数目
上面的tpcds用例在stage3的时候生成了4万多个task,而spark切分hdfs文件,调用的是Hadoop的API
由于tpcds用例的hdfs partition数目达到了几万个,调大mapreduce.input.fileinputformat.split.minsize大小至512Mb,减少split数目。
但是测试调整后没有起效果,后面估计得问问spark的同学,感觉如果能减少split数目将提高不少时间。
brocast vs shuffle join
我们的实时表达到了几T,维度表只有几十Kb,有一张纬度表在28Mb左右,而默认的spark.sql.autoBroadcastJoinThreshold是10Mb。所以我们将其值修改到了50mb,改变了执行计划,但是性能提高不多,只有提高了2%左右。在spark-ui的SQL可以看到执行计划:
以下是brocast和shuffle的对比:
影响参数: spark.sql.autoBroadcastJoinThreshold: join表采用brocast方式的大小阀值
假如A 10T, B 50m,A和B发生join。
brocast流程:
如果spark.sql.autoBroadcastJoinThreshold设置为50M,那么B表采用的是brocast方式。B表数据会拉到driver上,然后广播到每个A表的executor,executor拿到B表数据后A表的每个partition做join操作,最后输出结果。这个过程产生executor个数*50M流量消耗。
如果采用的shuffle流程,两个表都要做shuffle,多出了大表的shuffle过程和对应的网络开销
总结
经过以上优化思路,最后我们将spark 参数定格在
--conf spark.io.compression.codec=lzf --conf spark.default.parallelism=1024 --conf spark.sql.shuffle.partitions=1024 --conf spark.memory.offHeap.enabled=true --conf spark.memory.offHeap.size=2147483648 --conf spark.serializer=org.apache.spark.serializer.KryoSerializer --conf spark.sql.autoBroadcastJoinThreshold=52428800 --num-executors 160 --executor-cores 6 --executor-memory 11G --conf spark.eventLog.enabled=false --conf spark.ui.enabled=false --conf spark.acls.enable=false --conf spark.authenticate=false --conf spark.network.crypto.enabled=false --conf spark.shuffle.memoryFraction=0.6 --conf spark.storage.memoryFraction=0.8
前后结果对比,总时间提高5分钟左右:
ycsb
ycsb是Yahoo 公司的一个用来对云服务进行基础测试的工具。目标是促进新一代云数据服务系统的性能比较。为四个广泛使用的系统(Cassandra,、HBase、PNUTS和一个简单的片式MySQL执行)订了套核心基准测试和结果报告。
https://github.com/brianfrankcooper/YCSB
优化思路
ycsb优化是比较有针对性的,分别针对读写过程,将相关影响到环节逐一优化,相关文档见:
大数据套件之HBase性能测试-andrewcheng.pdf