spark性能优化点(1)

1. 分配更多的资源
 
 
1.1 分配哪些资源
 
 
1.2 在哪里可以设置这些资源
 
 
1.3 参数调节到多大,算是最大
 
 
分配更多的资源:
 
 
它是性能优化调优的王道,就是增加和分配更多的资源,这对于性能和速度上的提升是显而易见的,
 
 
基本上,在一定范围之内,增加资源与性能的提升,是成正比的;写完了一个复杂的 spark 作业之后,进行性能调
 
 
优的时候,首先第一步,就是要来调节最优的资源配置;在这个基础之上,如果说你的 spark 作业,能够分配的资源达到
 
 
了你的能力范围的顶端之后,无法再分配更多的资源了,公司资源有限;那么才是考虑去做后面的这些性能调优的点。
 
 
相关问题:
 
 
1 )分配哪些资源?
 
 
2 )在哪里可以设置这些资源?
 
 
3 )剖析为什么分配这些资源之后,性能可以得到提升?
 
 
executor‐memory executor‐cores 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 1.4 为什么调大资源以后性能可以提升
 
 
2. 提高并行度
 
 
2.1 Spark 的并行度指的是什么
 
 
第一种情况: 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.2 如何提高并行度
 
 
2.2.1 可以设置 task 的数量
 
 
2.2.2 如何设置 task 数量来提高并行度
 
 
2.2.3 RDD 重新设置 partition 的数量
 
 
spark 作业中,各个 stage task 的数量,也就代表了 spark 作业在各个阶段 stage 的并行度!
 
 
当分配完所能分配的最大资源了,然后对应资源去调节程序的并行度,如果并行度没有与资源相匹配,那么导致你
 
 
分配下去的资源都浪费掉了。同时并行运行,还可以让每个 task 要处理的数量变少(很简单的原理。合理设置并行度,
 
 
可以充分利用集群资源,减少每个 task 处理数据量,而增加性能加快运行速度。)
 
 
举例说明:
 
 
假如, 现在已经在 spark‐submit 脚本里面,给我们的 spark 作业分配了足够多的资源,比如 50 executor ,每
 
 
executor 10G 内存,每个 executor 3 cpu core 。 基本已经达到了 spark 集群或者 yarn 集群上限。 task 没有
 
 
设置,或者设置的很少,比如就设置了 100 task 50 executor 、每个 executor 3 core ,也就是说
 
 
Application 任何一个 stage 运行的时候,都有总数 150 cpu core ,可以并行运行。
 
 
但是你现在只有 100 task ,平均分配一下,每个 executor 分配到 2 task ,那么同时在运行的 task ,只有 100
 
 
task ,每个 executor 只会并行运行 2 task 。 每个 executor 剩下的一个 cpu core 就浪费掉了!你的资源,虽然分
 
 
配充足了,但是问题是, 并行度没有与资源相匹配,导致你分配下去的资源都浪费掉了。合理的并行度的设置,应该要
 
 
设置的足够大,大到可以完全合理的利用你的集群资源; 比如上面的例子,总共集群有 150 cpu core ,可以并行运
 
 
150 task 。那么你就应该将你的 Application 的并行度,至少设置成 150 个,才能完全有效的利用你的集群资源,
 
 
150 task 并行执行,而且 task 增加到 150 个以后,即可以同时并行运行,还可以让每个 task 要处理的数量变少; 比
 
 
如总共 150G 的数据要处理, 如果是 100 task ,每个 task 要计算 1.5G 的数据。 现在增加到 150 task ,每个 task
 
 
要处理 1G 数据。
 
 
至少设置成与 spark Application 的总 cpu core 数量相同(最理想情况, 150 core ,分配 150task ,一起运
 
 
行,差不多同一时间运行完毕)官方推荐, task 数量,设置成 spark Application cpu core 数量的 2~3 倍 。
 
 
比如 150 cpu core ,基本设置 task 数量为 300~500. 与理想情况不同的,有些 task 会运行快一点,比如 50s 就完
 
 
了,有些 task 可能会慢一点,要一分半才运行完,所以如果你的 task 数量,刚好设置的跟 cpu core 数量相同,可能会
 
 
导致资源的浪费。
 
 
因为比如 150 task 10 个先运行完了,剩余 140 个还在运行,但是这个时候,就有 10 cpu core 空闲出来了,导
 
 
致浪费。如果设置 2~3 倍,那么一个 task 运行完以后,另外一个 task 马上补上来,尽量让 cpu core 不要空闲。同时尽量
 
 
提升 spark 运行效率和速度。提升性能。
 
 
设置参数 spark.defalut.parallelism
 
 
默认是没有值的,如果设置了值为 10 ,它会在 shuffle 的过程才会起作用。
 
 
比如 val rdd2 = rdd1.reduceByKey(_+_)
 
 
此时 rdd2 的分区数就是 10 rdd1 的分区数不受这个参数的影响。
 
 
可以通过在构建 SparkConf 对象的时候设置,例如:
 
 
new SparkConf().set("spark.defalut.parallelism","500")
 
 
使用 rdd.repartition 来重新分区,该方法会生成一个新的 rdd ,使其分区数变大。
 
 
此时由于一个 partition 对应一个 task ,那么对应的 task 个数越多,通过这种方式也可以提高并行度。 2.2.4 提高 sparksql 运行的 task 数量
 
 
3. RDD 的重用和持久化
 
 
3.1 实际开发遇到的情况说明
 
 
3.2 如何对 rdd 进行持久化
 
 
3.3 rdd 持久化的时可以采用序列化
 
 
通过设置参数 spark.sql.shuffle.partitions=500 默认为 200
 
 
可以适当增大,来提高并行度。 比如设置为 spark.sql.shuffle.partitions=500
 
 
如上图所示的计算逻辑:
 
 
1 )当第一次使用 rdd2 做相应的算子操作得到 rdd3 的时候,就会从 rdd1 开始计算,先读取 HDFS 上的文件,然后对 rdd1
 
 
做对应的算子操作得到 rdd2, 再由 rdd2 计算之后得到 rdd3 。同样为了计算得到 rdd4 ,前面的逻辑会被重新计算。
 
 
3 )默认情况下多次对一个 rdd 执行算子操作,去获取不同的 rdd ,都会对这个 rdd 及之前的父 rdd 全部重新计算一次。
 
 
这种情况在实际开发代码的时候会经常遇到,但是我们一定要避免一个 rdd 重复计算多次,否则会导致性能急剧降低。
 
 
总结:可以把多次使用到的 rdd ,也就是公共 rdd 进行持久化,避免后续需要,再次重新计算,提升效率。
 
 
可以调用 rdd cache 或者 persist 方法。
 
 
1 cache 方法默认是把数据持久化到内存中 ,例如: rdd.cache ,其本质还是调用了 persist 方法
 
 
2 persist 方法中有丰富的缓存级别,这些缓存级别都定义在 StorageLevel 这个 object 中,可以结合实际的应用场
 
 
景合理的设置缓存级别。例如: rdd.persist(StorageLevel.MEMORY_ONLY), 这是 cache 方法的实现。 3.4 广播变量的使用
 
 
3.4.1 场景描述
 
 
在实际工作中可能会遇到这样的情况,由于要处理的数据量非常大,这个时候可能会在一个 stage 中出现大量的
 
 
task ,比如有 1000 task ,这些 task 都需要一份相同的数据来处理业务,这份数据的大小为 100M ,该数据会拷贝
 
 
1000 份副本,通过网络传输到各个 task 中去,给 task 使用。这里会涉及大量的网络传输开销,同时至少需要的内存
 
 
1000*100M=100G ,这个内存开销是非常大的。不必要的内存的消耗和占用,就导致了,你在进行 RDD 持久化
 
 
到内存,也许就没法完全在内存中放下;就只能写入磁盘,最后导致后续的操作在磁盘 IO 上消耗性能;这对于
 
 
spark 任务处理来说就是一场灾难。
 
 
由于内存开销比较大, task 在创建对象的时候,可能会出现堆内存放不下所有对象,就会导致频繁的垃圾回收器的
 
 
回收 GC GC 的时候一定是会导致工作线程停止,也就是导致 Spark 暂停工作那么一点时间。频繁 GC 的话,对
 
 
Spark 作业的运行的速度会有相当可观的影响。
 
 
3.4.2 广播变量引入
 
 
Spark 中分布式执行的代码需要传递到各个 executor task 上运行。对于一些只读、固定的数据 , 每次都需要 Driver
 
 
广播到各个 Task 上,这样效率低下。广播变量允许将变量只广播(提前广播)给各个 executor 。该 executor 上的各
 
 
task 再从所在节点的 BlockManager( 负责管理某个 executor 对应的内存和磁盘上的数据 ) 获取变量,而不是从
 
 
Driver 获取变量,从而提升了效率。
 
 
1 )如果正常将数据持久化在内存中,那么可能会导致内存的占用过大,这样的话,也许会导致 OOM 内存溢出。
 
 
2 )当纯内存无法支撑公共 RDD 数据完全存放的时候,就优先考虑使用序列化的方式在纯内存中存储。将 RDD 的每个
 
 
partition 的数据,序列化成一个字节数组;序列化后,大大减少内存的空间占用。
 
 
3 )序列化的方式,唯一的缺点就是,在获取数据的时候,需要反序列化。但是可以减少占用的空间和便于网络传输
 
 
4 )如果序列化纯内存方式,还是导致 OOM ,内存溢出;就只能考虑磁盘的方式,内存 + 磁盘的普通方式(无序列化)。
 
 
5 )为了数据的高可靠性,而且内存充足,可以使用双副本机制,进行持久化
 
 
持久化的双副本机制,持久化后的一个副本,因为机器宕机了,副本丢了,就还是得重新计算一次;
 
 
持久化的每个数据单元,存储一份副本,放在其他节点上面,从而进行容错;
 
 
一个副本丢了,不用重新计算,还可以使用另外一份副本。这种方式,仅仅针对你的内存资源极度充足。
 
 
比如 : StorageLevel.MEMORY_ONLY_2 3.4.3 使用广播变量后的性能分析
 
 
3.4.4 如何使用广播变量
 
 
广播变量,初始的时候,就在 Drvier 上有一份副本。通过在 Driver 把共享数据转换成广播变量。
 
 
task 在运行的时候,想要使用广播变量中的数据,此时首先会在自己本地的 Executor 对应的 BlockManager 中,尝
 
 
试获取变量副本;如果本地没有,那么就从 Driver 远程拉取广播变量副本,并保存在本地的 BlockManager 中;
 
 
此后这个 executor 上的 task ,都会直接使用本地的 BlockManager 中的副本。那么这个时候所有该 executor 中的
 
 
task 都会使用这个广播变量的副本。也就是说一个 executor 只需要在第一个 task 启动时,获得一份广播变量数据,之后
 
 
task 都从本节点的 BlockManager 中获取相关数据。
 
 
executor BlockManager 除了从 driver 上拉取,也可能从其他节点的 BlockManager 上拉取变量副本,网络距离
 
 
越近越好。
 
 
比如一个任务需要 50 executor 1000 task ,共享数据为 100M
 
 
(1) 在不使用广播变量的情况下, 1000 task ,就需要该共享数据的 1000 个副本,也就是说有 1000 份数需要大量的网络
 
 
传输和内存开销存储。耗费的内存大小 1000*100=100G.
 
 
(2) 使用了广播变量后, 50 executor 就只需要 50 个副本数据,而且不一定都是从 Driver 传输到每个节点,还可能是就
 
 
近从最近的节点的 executor blockmanager 上拉取广播变量副本,网络传输速度大大增加;内存开销 50*100M=5G
 
 
总结:
 
 
不使用广播变量的内存开销为 100G ,使用后的内存开销 5G ,这里就相差了 20 倍左右的网络传输性能损耗和内存开
 
 
销,使用广播变量后对于性能的提升和影响,还是很可观的。
 
 
广播变量的使用不一定会对性能产生决定性的作用。比如运行 30 分钟的 spark 作业,可能做了广播变量以后,速度
 
 
快了 2 分钟,或者 5 分钟。但是一点一滴的调优,积少成多。最后还是会有效果的。 4. 使用 Kryo 序列化
 
 
4.1 spark 序列化介绍
 
 
4.2 Kryo 序列化启用后生效的地方
 
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值