文章目录
- 一、Spark作业资源的设置情况
- 二、DataFrame/Dataset/RDD的区别及编程
- 三、Spark中的隐式转换的作用:结合Scala来学习
一、Spark作业资源的设置情况
性能调优的王道,就是增加和分配更多的资源,性能和速度上的提升是显而易见的,基本上,在一定范围之内,增加资源与性能的提升是成正比的。写完了一个复杂的Spark作业之后,进行性能调优的时候,首先第一步,就是要调节最优的资源配置,在这个基础之上,如果说你的Spark作业,能够分配的资源达到了你的能力范围的顶端之后,无法再分配更多的资源了,公司资源有限,那么才是考虑去做后面的这些性能调优的点。
1.分配哪些资源:
executor、每个executor的cpu core数量 、每个executor的memory大小、driver memory。
2.在哪里分配这些资源:
在我们在生产环境中,提交spark作业时,用的spark-submit shell脚本,里面调整对应的参数。参数如下:
/usr/local/spark/bin/spark-submit \
--class cn.spark.sparktest.core.WordCountCluster \
--num-executors 3 \ 配置executor的数量
--driver-memory 100m \ 配置driver的内存(影响不大)
--executor-memory 100m \ 配置每个executor的内存大小
--executor-cores 3 \ 配置每个executor的cpu core数量
/usr/local/SparkTest-0.0.1-SNAPSHOT.jar \
3.调节到多大,算是资源利用率最大呢:
Spark Standalone,公司集群上,搭建了一套Spark集群,你应该了解每台机器还能够给你使用的资源情况,比如:大概有多少内存,多少cpu core,那么,设置的时候就根据这个实际的情况,去调节每个Spark作业的资源分配。比如说你的每台机器能够给你使用4G内存,2个cpu core;20台机器,如果设置executor数量为20个,那么每个executor就分配4G内存,2个cpu core。
Yarn 资源队列,需要查看你要提交的yarn资源队列目前的资源剩余及使用情况,然后根据剩余可用的资源进行合理分配设置,比如:500G内存,100个cpu core,如果设置executor数量为50个,那么每个executor就平均最大分配10G内存,2个cpu core,你能使用的资源有多大,就尽量去调节到最大的大小。
4.为什么调节了资源以后,性能可以提升:
增加executor数量:如果executor数量比较少,那么,能够并行执行的task数量就比较少,就意味着,我们的Application的并行执行的能力就很弱。比如有3个executor,每个executor有2个cpu core,那么同时能够并行执行的task就是6个。6个执行完以后,再换下一批6个task执行。增加了executor数量以后,那么就意味着,能够并行执行的task数量,也就变多了。比如原先是6个,现在可能可以并行执行10个,甚至20个,100个,那么并行能力就比之前提升了数倍,相应的,性能(执行的速度),也能提升数倍~数十倍。
增加每个executor的内存大小:如果需要对RDD进行cache,那么更多的内存,就可以缓存更多的数据,将更少的数据写入磁盘,甚至不写入磁盘。减少了磁盘IO消耗。对于shuffle操作,在reduce端会需要内存来存放拉取的数据并进行聚合。如果内存不够,就会写入磁盘。如果给executor分配更多内存以后,可能就只需要将很少量的数据写入磁盘,甚至不需要写入磁盘,减少了磁盘IO,提升了性能。对于task的执行,可能会创建很多对象,如果内存比较小,可能会频繁导致JVM堆内存满了,然后频繁GC垃圾回收。内存加大以后,会很少的触发GC,提高了程序的运行速度。
增加每个executor的cpu core:增加每个executor的cpu core,也是增加了task执行的并行度。因为同一时间每个cpu core只能调用执行一个executor进程中的一个task,那么如果原本20个executor,每个才2个cpu core,能够并行执行的task数量,也就是40个task。现在每个executor的cpu core,增加到了5个,那么能够并行执行的task数量,就是100个task。很明显的,执行的速度,提升了2.5倍。
5.调节Spark任务的并行度:
并行度:其实就是指的是,Spark作业中,各个stage的task数量,也就代表了Spark作业的在各个阶段(stage)的并行度。
a.为什么需要调节task的并行度:
假设,现在已经在spark-submit脚本里面,给我们的spark作业分配了足够多的资源,比如50个executor,每个executor有10G内存,每个executor有3个cpu core。基本已经达到了集群或者yarn队列的资源上限。task没有设置或者设置的很少,比如就设置了100个task,50个executor,每个executor有3个cpu core,也就是说,你的Application任何一个stage运行的时候,都有总数在150个cpu core,可以并行运行。但是你现在,只有100个task,平均分配一下,每个executor分配到2个task,那么同时在运行的task,只有100个,每个executor只会并行运行2个task。每个executor剩下的一个cpu core,就浪费掉了。你的资源虽然分配足够了,但是问题是,并行度没有与资源相匹配,导致你分配下去的资源都浪费掉了。
b.如何合理的设置task的并行度:
合理的并行度的设置,应该是要设置的足够大,大到可以完全合理的利用你的集群资源,比如上面的例子,总共集群有150个cpu core,可以并行运行150个task。那么就应该将你的Application的并行度,至少设置成150,才能完全有效的利用你的集群资源,让150个task并行执行,而且task增加到150个以后,即可以同时并行运行,还可以让每个task要处理的数据量变少,比如总共150G的数据要处理,如果是100个task,每个task计算1.5G的数据;现在增加到150个task,可以并行运行,而且每个task主要处理1G的数据就可以。只要合理设置并行度,就可以完全充分利用你的集群计算资源,并且减少每个task要处理的数据量,最终,就是提升你的整个Spark作业的性能和运行速度。
- task数量,至少设置成与Spark application的总cpu core数量相同(最理想情况,比如总共150个cpu core,分配了150个task,一起运行,差不多同一时间运行完毕)
- 官方是推荐task数量,设置成spark application总cpu core数量的2~3倍,比如150个cpu core,基本要设置task数量为300~500。实际情况,与理想情况不同的,有些task会运行的快一点,比如50s就完了,有些task,可能会慢一点,要1分半才运行完,所以如果你的task数量,刚好设置的跟cpu core数量相同,可能还是会导致资源的浪费,因为,比如150个task,10个先运行完了,剩余140个还在运行,但是这个时候,有10个cpu core就空闲出来了,就导致了浪费。那如果task数量设置成cpu core总数的2~3倍,那么一个task运行完了以后,另一个task马上可以补上来,就尽量让cpu core不要空闲,同时也是尽量提升spark作业运行的效率和速度,提升性能。
- Spark Application的并行度怎么设置呢?Spark的并行度参数为spark.default.parallelism,需要我们在driver端代码中进行设置,SparkConf conf = new SparkConf().set(“spark.default.parallelism”, “500”)
二、DataFrame/Dataset/RDD的区别及编程
可
1.前言:
Spark每个模块都有一个核心抽象,Spark-core的核心抽象是RDD,Spark SQL等都基于RDD封装了自己的抽象,在Spark SQL中是DataFrame/DataSet。相对来说RDD是更偏底层的抽象,DataFrame/DataSet是在其上做了一层封装,做了优化,使用起来更加方便。从功能上来说,DataFrame/DataSet能做的事情RDD都能做,RDD能做的事情DataFrame/DataSet不一定能做。
从版本的产生上来看:RDD (Spark1.0) —> Dataframe(Spark1.3) —> Dataset(Spark1.6)
如果同样的数据都给到这三个数据结构,他们分别计算之后,都会给出相同的结果。不同是的他们的执行效率和执行方式。
2.什么是DataFrame:
在Spark中,DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。
3.RDD和DataFrame的区别:
DataFrame与RDD的主要区别在于,DataFrame带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。使得Spark SQL得以洞察更多的结构信息,从而对藏于DataFrame背后的数据源以及作用于DataFrame之上的变换进行了针对性的优化,最终达到大幅提升运行时效率的目标。
RDD,由于无从得知所存数据元素的具体内部结构,Spark Core只能在stage层面进行简单、通用的流水线优化。 DataFrame底层是以RDD为基础的分布式数据集,和RDD的主要区别的是:RDD中没有schema信息,而DataFrame中数据每一行都包含schema。DataFrame = RDD[Row] + shcema
DataFrame还引入了off-heap,意味着JVM堆以外的内存, 这些内存直接受操作系统管理(而不是JVM)。Spark能够以二进制的形式序列化数据(不包括结构)到off-heap中,当要操作数据时,就直接操作off-heap内存。由于Spark理解schema,所以知道该如何操作。
off-heap就像地盘, schema就像地图,Spark有地图又有自己地盘了,就可以自己说了算了,不再受JVM的限制,也就不再收GC的困扰了。通过schema和off-heap,DataFrame解决了RDD的缺点,但是却丢了RDD的优点:DataFrame不是类型安全的,API也不是面向对象风格的。
4.什么是DataSet:
Dataset是一个由特定领域的对象组成强类型(typedrel)集合,可以使用函数(DSL)或关系运算(SQL)进行并行的转换操作。 每个Dataset 还有一个称为“DataFrame”的无类型(untypedrel)视图,它是[[Row]]的数据集。
5.RDD和Dataset的区别:
Dataset与RDD类似,但是,它们不使用Java序列化或Kryo,而是使用专用的Encoder编码器来序列化对象以便通过网络进行处理或传输。虽然Encoder编码器和标准序列化都负责将对象转换为字节,但Encoder编码器是动态生成的代码,并使用一种格式,允许Spark执行许多操作,如过滤,排序和散列,而无需将字节反序列化为对象
6.Dataset和DataFrame的区别与联系:
区别:
- Dataset是强类型typedrel的,会在编译的时候进行类型检测;而DataFrame是弱类型untypedrel的,在执行的时候进行类型检测;
- Dataset是通过Encoder进行序列化,支持动态的生成代码,直接在bytes的层面进行排序,过滤等的操作;而DataFrame是采用可选的java的标准序列化或是kyro进行序列化。
联系:
- 在spark2.x,DataFrame和Dataset的api进行了统一
- 在语法角度,DataFrame是Dataset中每一个元素为Row类型的特殊情况
type DataFrame = Dataset[Row] - DataFrame和Dataset实质上都是一个逻辑计划,并且是懒加载的,都包含着scahema信息,只有到数据要读取的时候,才会将逻辑计划进行分析和优化,并最终转化为RDD
- 二者由于api是统一的,所以都可以采用DSL和SQL方式进行开发,都可以通过sparksession对象进行创建或者是通过transform转化操作得到
- 在对DataFrame和Dataset进行操作许多操作都需要这个包进行支持
import spark.implicits._
7.DataSet的创建:
可以参见官方文档:http://spark.apache.org/docs/2.2.1/sql-programming-guide.html#creating-datasets
8.RDD转DataFrame原因及方式:
可以将RDD转成DataFrame之后,借用sparksql和sql以及HQL语句快速方便的使用sql语句统计和查询,比如说分组排名(row_number() over()) 分析函数和窗口函数去实现占比分析。
将RDD转化为DataFrame有两种方式:
方式一:通过反射推断schema 要求:RDD的元素类型必须是case class
方式二、编程指定schema 要求:RDD的元素类型必须是Row 自己编写schema(StructType) 调用SparkSession的createDatafrmame(RDD[Row],schema)
9.DataFrame转RDD原因及方式:
- 解决一些使用sql难以处理的统计分析
- 将数据写入Mysql。a.DataFrame的write.jdbc,仅支持四种模式:append、overwrite、ignore、default;b.使用rdd的话,除了上述以外还支持insert 和 update操作,还支持数据库连接池 (自定 义,第三方:c3p0 hibernate mybatis)方式,批量高效将大量数据写入 Mysql
方式: DataFrame转换为RDD相对来说比较简单,只需要调用DataFrame的RDD算子即可。
三、Spark中的隐式转换的作用:结合Scala来学习