一:常用调优参数
#配置文件,使用这个名称application.conf就可以自动读取
#以下是spark的调优参数
#自动广播
spark.sql.autoBroadcastJoinThreshold="10485760"
#spark sql shuffle并行度设置
spark.sql.shuffle.partitions="200"
#自动广播超时时间
#spark.sql.broadcastTimeout=""
#是否启动shuffle压缩
spark.shuffle.compress="true"
#shuffle失败重试次数
spark.shuffle.io.maxRetries="5"
#shuffle重试的间隔时间
spark.shuffle.io.retryWait="10s"
#广播是否启动压缩
spark.broadcast.compress="true"
#序列化机制
spark.serializer="org.apache.spark.serializer.KryoSerializer"
#存储与执行的内存比例
spark.memory.fraction="0.6"
#存储的内存比例
spark.memory.storageFraction="0.5"
#spark core shuffle并行度设置
spark.default.parallelism=200
#数据本地化等待时间
spark.locality.wait="3s"
#是否启动推测机制
spark.speculation.flag="true"
#推测机制启动时机
spark.speculation.multiplier="1.5"
二:常用优化方式介绍
1.:增加分配资源
1.executor-memory
2.executor-cores
3.num-executor
4.driver-memory
在实际的生产环境中,提交spark任务时,使用spark‐submit shell脚本,在里面调整对应的参数。
提交任务的脚本: spark‐submit \
‐‐master spark://node1:7077 \
‐‐class cn.itcast.WordCount \
‐‐num‐executors 3 \
配置executor的数量
‐‐driver‐memory 1g \
配置driver的内存(影响不大)
‐‐executor‐memory 1g
配置每一个executor的内存大小
‐‐executor‐cores 3 \
配置每一个executor的cpu个数
/export/servers/wordcount.jar
参数调到多大合适?
第一种情况:standalone模式 先计算出公司spark集群上的所有资源 每台节点的内存大小和cpu核数,
比如:一共有20台worker节点,每台节点8g内存,10个cpu。
实际任务在给定资源的时候,可以给20个executor、每个executor的内存8g、每个executor的使用的cpu个数 10。
第二种情况:Yarn 先计算出yarn集群的所有大小,比如一共500g内存,100个cpu;
这个时候可以分配的大资源,比如给定50个executor、每个executor的内存大小10g,每个executor使用的cpu 个数为2。
使用原则:你能使用的资源有多大,就尽量去调节到大的大小(executor的数量:几十个到上百个不等;executor的 内存;exector的cpu个数)
2.提高并行度
并行度的设置原则:
1.至少需要设置为cpu的核数 = task的个数,这样保证不浪费资源,但是问题还有:就是当有的task执行快,其他的执行慢,就会造成执行快的task中的资源空闲下来,也会浪费
2.设置为cpu核数的2~3倍最理想,保证资源充分利用
如何设置?
#spark sql shuffle并行度设置
spark.sql.shuffle.partitions="200"
#spark core shuffle并行度设置
spark.default.parallelism=200
这两种设置方式分别是提高sql和core的并行度,默认都是200,根据数据量可以设置到500或以上
3.RDD重用(公共rdd持久化)
原因:
由于RDD是惰性求值,每次执行Action算子,都会从开始的RDD执行,知道末尾RDD,求得数据
如何进行持久化?
1.rdd.cache 默认方式就是MEMORY_ONLY
2.rdd.persist(StorageLevel.MEMORY_ONLY) 可以根据业务需要进行存储级别的设置
如何持久化同时进行序列化?
(1)如果正常将数据持久化在内存中,那么可能会导致内存的占用过大,这样的话,也许会导致OOM内存溢出。
(2)当纯内存无法支撑公共RDD数据完全存放的时候,就优先考虑使用序列化的方式在纯内存中存储。将RDD的每个 partition的数据,序列化成一个字节数组;序列化后,大大减少内存的空间占用。
(3)序列化的方式,唯一的缺点就是,在获取数据的时候,需要反序列化。但是可以减少占用的空间和便于网络传输
(4)如果序列化纯内存方式,还是导致OOM,内存溢出;就只能考虑磁盘的方式,内存+磁盘的普通方式(无序列化)。
(5)为了数据的高可靠性,而且内存充足,可以使用双副本机制,进行持久化 持久化的双副本机制,持久化后的一个副本,因为机器宕机了,副本丢了,就还是得重新计算一次;
持久化的每个数据单元,存储一份副本,放在其他节点上面,从而进行容错;
一个副本丢了,不用重新计算,还可以使用另外一份副本。这种方式,仅仅针对你的内存资源极度充足。
比如: StorageLevel.MEMORY_ONLY_2
4.广播变量
为何进行广播变量?
1.广播前 ,100 个task需要拉取100次共享数据
2.广播后,每个executor只需要一份数据,而每个executor中有多个task,减少共享数据的IO次数
广播变量的使用场景:
1.小表join大表的时候,把小表广播出去
2.多个task使用共享数据的时候,把共享数据广播出去
如何进行广播?
1.SparkCore:
spark.sparkcontext.broadcast(需要广播的数据)
2.SparkSQL
1.先设置广播小表的容量设置,默认10M大小,实际工作中可以设置为2-3G,前提是把Driver的内存设置5-10G,否则无法存储
#自动广播
spark.sql.autoBroadcastJoinThreshold="10485760"
#自动广播超时时间
#spark.sql.broadcastTimeout=""
#广播是否启动压缩
spark.broadcast.compress="true"
2.代码设置保证广播设置的有效实施,否则就算设置了自动广播也不一定就会进行广播
spark.sql(" cache table 小表名称")
5.使用Kryo进行序列化
为什么要是有Kryo进行序列化?
因为在处理数据的时候需要进行网络传输,而网络IO必然浪费大量资源,高效的序列化手段有效减少内存占比,和资源消耗
所以,Kryo的序列化机制比Java的序列化机制高效,数据只有java的1/10,所以更加适合
如何启动Kryo的序列化?
#序列化机制
spark.serializer="org.apache.spark.serializer.KryoSerializer"
Kryo序列化机制,一旦启用以后,会生效的几个地方:
(1)算子函数中使用到的外部变量
算子中的外部变量可能来着与driver需要涉及到网络传输,就需要用到序列化。
终可以优化网络传输的性能,优化集群中内存的占用和消耗
(2)持久化RDD时进行序列化,StorageLevel.MEMORY_ONLY_SER
将rdd持久化时,对应的存储级别里,需要用到序列化。
终可以优化内存的占用和消耗;持久化RDD占用的内存越少,task执行的时候,创建的对象,就不至于频繁 的占满内存,频繁发生GC。
(3) 产生shuffle的地方,也就是宽依赖
下游的stage中的task,拉取上游stage中的task产生的结果数据,跨网络传输,需要用到序列化。
终可以优化网络传输的性
6.数据本地化等待时间
数据本地化的四个级别:
(1)PROCESS_LOCAL:进程本地化 代码和数据在同一个进程中,也就是在同一个executor中;计算数据的task由executor执行,数据在executor的 BlockManager中;性能好
(2)NODE_LOCAL:节点本地化 代码和数据在同一个节点中;比如说数据作为一个HDFS block块,就在节点上,而task在节点上某个executor中 运行;或者是数据和task在一个节点上的不同executor中;数据需要在进程间进行传输;性能其次
(3)RACK_LOCAL:机架本地化 数据和task在一个机架的两个节点上;数据需要通过网络在节点之间进行传输; 性能比较差
(4) ANY:无限制 数据和task可能在集群中的任何地方,而且不在一个机架中;性能差
如何设置本地等待时长?
#1.数据本地化等待时间,默认3秒
spark.locality.wait="3s"
这种方式最常用,可以根据进程本地化-->节点本地化-->机架本地化-->无限制 如果超过等待时长就依次类推,执行最高效的本地化
#2.另外还有指定本地位置的等待时长
spark.locality.wait.node
spark.locality.wait.process
spark.locality.wait.rack
注:
两种方式不可同时使用
别为了本地化而耗费太多的等待时长,本末倒置,如果数据量比较大的时候可以设置到5-8秒
7.内存调优
1.spark内存参数调整
如何调整?
#存储与执行的内存比例
spark.memory.fraction="0.6"
#存储的内存比例
spark.memory.storageFraction="0.5"
注:
如果在界面看到GC时长特别长,说明存储对象空间太小,为了腾空间而触发了GC的执行
这时候就可以调高内存executor-memory 或者调高执行区的与存储区的内存比例,同时也可以调小存储区的内存占比
2.JVM的内存机制,为什么会触发GC?
如果在GC的时候造成拉取数据失败怎么办?
重试,如何重试?
#shuffle失败重试次数
spark.shuffle.io.maxRetries="5"
#shuffle重试的间隔时间
spark.shuffle.io.retryWait="10s"
8.启动推测机制
为什么要开启推测机制?
因为任务执行过程可能有的任务在执行过程中会发生异常,导致执行时间大大增加
推测机制根据这种情况开启另外一个任务去执行相同的任务,最终以最早执行完成的任务的数据为结果数据
避免无限等待任务的执行时长
如何开启?
#是否启动推测机制
spark.speculation.flag="true"
#推测机制启动时机
spark.speculation.multiplier="1.5"