spark性能优化

1.分配更多的资源: 它是性能优化调优的王道,就是增加和分配更多的资源,这对于性能和速度上的提升是显而易见的,基本上,在一定范围之内,增加资源与性能的提升,是成正比的;写完了一个复杂的spark作业之后,进行性能调优的时候,首先第一步,就是要来调节最优的资源配置;在这个基础上,如果说你的spark作业,能够分配的资源达到了你的能力范围的顶端之后,无法在分配更多的资源了,公司资源有限,那么才是考虑去做后面的这些性能的调优的点。
1.1.参数调节到多大,算是最大: 第一种情况:standalone模式 先计算出公司spark集群上的所有资源,每台节点的内存大小和核数; 比如:一共有20台worker节点,每台节点8G内存,10个cup。实际任务在给定资源的时候,可以给20个executor,每个executor的内存8g,每个executor的使用cup个数10; 第二种情况:yarn:先计算出yarn集群的多有大小,比如一共500g内存,100个cup;这个时候可以分配的最大资源,比如给定50个executor,每个executor的内存大小是10g,每个executor的使用的cup个数为2;
使用原则:你能使用的资源有多大,就尽量去调节到最大的大小(executor的数量:几十个到上百个不等,executor的内存:executor的个数)

2.提高并行度 spark的并行度指的是什么:spark作业中,各个stage的task的数量,也就代表了spark作业在各个阶段stage的并行度! 当分配完所能分配的最大的资源了,然后对应资源程序的并行度,如果并行度没有与资源相匹配,那么导致你分配下去的资源都浪费掉了,同时并行运行,还可以让每个task要处理的数量变少(很简单的原理,合理设置并行度,可以充分利用集群资源,减少每个task处理数据量,而增加性能加快运行速度)
2.2如何提高并行度 设置task的数量: 至少设置成与spark application的总cup core数量相同(最理想情况,150个core,分配150task,一起运行,差不多同一时间运行完毕)官方推荐,task数量,设置成spark application总cup core数量的2~3倍。
给rdd重新设置parition的数量:使用rdd.repartition来重新分区,该方法会生成一个新的rdd,使其分区数变大,此时由于一个partition对应一个task,那么对应的task个数越多,通过这种方式也可以提高并行度。
提高sparksql运行的task数量:通过设置参数 spark.sql.shuffle.partition=500 默认是200;可以适当调大,来提高并行度。
rdd的重用和持久化: 在这里插入图片描述
(1)当第一次使用rdd2做相应的算子操作得到rdd3的时候,就会从rdd1开始计算,先读取HDFS上的文件,然后对rdd1 做对应的算子操作得到rdd2,再由rdd2计算之后得到rdd3。同样为了计算得到rdd4,前面的逻辑会被重新计算。 (3)默认情况下多次对一个rdd执行算子操作,去获取不同的rdd,都会对这个rdd及之前的父rdd全部重新计算一次。 这种情况在实际开发代码的时候会经常遇到,但是我们一定要避免一个rdd重复计算多次,否则会导致性能急剧降低。 总结:可以把多次使用到的rdd,也就是公共rdd进行持久化,避免后续需要,再次重新计算,提升效率。
在这里插入图片描述
如何对rdd进行持久化 可以调用rdd的cache或者presist方法。
(1)cache方法默认是把数据持久化到内存中 ,例如:rdd.cache ,其本质还是调用了persist方法 (2)persist方法中有丰富的缓存级别,这些缓存级别都定义在StorageLevel这个object中,可以结合实际的应用场 景合理的设置缓存级别
rdd持久化的时可以采用序列化 :(1)如果正常将数据持久化在内存中,那么可能会导致内存的占用过大,这样的话,也许会导致OOM内存溢出。 (2)当纯内存无法支撑公共RDD数据完全存放的时候,就优先考虑使用序列化的方式在纯内存中存储。将RDD的每个 partition的数据,序列化成一个字节数组;序列化后,大大减少内存的空间占用。 (3)序列化的方式,唯一的缺点就是,在获取数据的时候,需要反序列化。但是可以减少占用的空间和便于网络传输 (4)如果序列化纯内存方式,还是导致OOM,内存溢出;就只能考虑磁盘的方式,内存+磁盘的普通方式(无序列化)。 (5)为了数据的高可靠性,而且内存充足,可以使用双副本机制,进行持久化 持久化的双副本机制,持久化后的一个副本,因为机器宕机了,副本丢了,就还是得重新计算一次; 持久化的每个数据单元,存储一份副本,放在其他节点上面,从而进行容错; 一个副本丢了,不用重新计算,还可以使用另外一份副本。这种方式,仅仅针对你的内存资源极度充足
广播变量的使用:场景描述,在实际工作中可能会遇到这样的情况,由于要处理的数据量非常大,这个时候可能会在一个stage中出现大量的 task,比如有1000个task,这些task都需要一份相同的数据来处理业务,这份数据的大小为100M,该数据会拷贝 1000份副本,通过网络传输到各个task中去,给task使用。这里会涉及大量的网络传输开销,同时至少需要的内存 为1000100M=100G,这个内存开销是非常大的。不必要的内存的消耗和占用,就导致了,你在进行RDD持久化 到内存,也许就没法完全在内存中放下;就只能写入磁盘,后导致后续的操作在磁盘IO上消耗性能;这对于 spark任务处理来说就是一场灾难。
由于内存开销比较大,task在创建对象的时候,可能会出现堆内存放不下所有对象,就会导致频繁的垃圾回收器的 回收GC。GC的时候一定是会导致工作线程停止,也就是导致Spark暂停工作那么一点时间。频繁GC的话,对 Spark作业的运行的速度会有相当可观的影响
在这里插入图片描述
广播变量引入:Spark中分布式执行的代码需要传递到各个executor的task上运行。对于一些只读、固定的数据,每次都需要Driver 广播到各个Task上,这样效率低下。广播变量允许将变量只广播(提前广播)给各个executor。该executor上的各 个task再从所在节点的BlockManager(负责管理某个executor对应的内存和磁盘上的数据)获取变量,而不是从 Driver获取变量,从而提升了效率
在这里插入图片描述
广播变量,初始的时候,就在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分钟。但是一点一滴的调优,积少成多。后还是会有效果的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值