Spark core 04(调优)

Collect:扫描所有分区拉取数据,拼接起来输出到driver(数据量大慎用)
    collect
    countByKey(Key多慎用)
    countByValue(Value多慎用)
    collectAsMap(数据量大慎用,一般配合广播变量使用)
take:扫描一个分区拉取数据,拼接起来输出到driver

groupByKey vs reduceByKey
reduceByKey:
shuffle之前在map端做了一次预聚合操作
groupByKey:直接shuffle,所以shuffle的数据量比reduceByKey大不少

Shared Variables:Spark does provide two limited types of shared variables for two common usage patterns: broadcast variables and accumulators.
accumulators:仅支持add,如用其他算法须自行注册
案例

scala> val accum = sc.longAccumulator("My Accumulator")
accum: org.apache.spark.util.LongAccumulator = LongAccumulator(id: 0, name: Some(My Accumulator), value: 0)

scala> sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum.add(x))
...
10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s

scala> accum.value
res2: Long = 10

broadcast :以这种方式广播的数据以序列化的形式缓存,然后在运行每个任务之前反序列化。
案例

scala> val broadcastVar = sc.broadcast(Array(1, 2, 3))
broadcastVar: org.apache.spark.broadcast.Broadcast[Array[Int]] = Broadcast(0)

scala> broadcastVar.value
res0: Array[Int] = Array(1, 2, 3)

Data Serialization:那些会让对象序列化过程缓慢,或是会消耗大量字节存储的序列化格式会大大降低计算速率。通常这会用户在优化Spark应用程序中的第一件事。Spark旨在在便利(允许您使用您的操作中的任何Java类型)和性能之间实现平衡。它提供了下面两种序列化库:
Spark调优(数据序列化和内存调优)

  1. Java serialization:Spark默认使用Java的ObjectOutputStream框架来序列化对象,可以对任何实现了java.io.Serializable的任何类进行序列化。用户也可以通过继承来实现更紧密的序列化性能控制。
  2. Kryo serialization:Spark也可以使用Kryo库(version 2)来实现更快的对象序列化。Kryo比Java序列化更快、数据格式更紧凑,但不支持所有的Serializable类型。用户如果希望使用Kryo来获取更好的性能,需要先去注册应用程序中会使用到的类。

spark内存管理详解

Determining Memory Consumption:
   调整数据集所需的内存消耗量的最佳方法是创建一个RDD,将其放入缓存,并查看web UI中的“Storage”页面。这个页面会告诉你RDD占用了多少内存。
  为了估计特定对象的内存消耗,使用SizeEstimator的估计方法。这对于试验不同的数据布局来减少内存使用以及确定广播变量在每个执行器堆上占据的空间量很有用。 

垃圾回收调优 (GC调优):

  • 检查gc统计中是否发生了过多的gc,如果full gc在一个task中发生了过多次,用户需考虑适当添加executor内存。
  • 如果minor GC较多,major GC/full GC 较少,尝试分配多点内存给Eden。你可以根据你自己的task的大致使用内存来估计eden区大小 E ,因此 young区大小一般为 4/3 * E 。使用Java参数 -Xmn=4/3*E
  • 如果GC统计中 old 接近满了,则适当降低spark.memory.fraction,毕竟减少点缓存比GC影响执行性能更能让人接受。或者,考虑减少young大小;或者,调大JVM的NewRatio参数,大部分JVM该值默认为2,表示old 占了2/3的堆内存,这个比例应当足够大,且比spark.memory.fraction 的比例大。
  • 尝试 G1 GC -XX:+UseG1GC。在一些大堆 JVM的场景下,有助于提高gc性能。G1需要额外的堆空间进行对象移动,考虑调大-XX:G1HeapRegionSize
  • 举个例子,如果你的task在从HDFS读取数据,task的内存使用可根据读取的HDFS block大小来估计。需注意通常一个解压的block是原block的2-3倍大,假设一个executor有个3-4个task在运行,HDFS block size为128M,那么eden区大小考虑为4 * 3 * 128 MB
  • 每当使用新配置后,需继续监控GC的耗时及频率。

Level of Parallelism:
  如果并行度设置不够高,集群资源可能不能被较充分利用。Spark默认会根据textFile文件数或parallelize的去设置map task的个数,reduce task的个数默认则使用最大的父RDD的分区数。用户可通过设置大多数并行方法的第二个参数指定并行度或修改默认配置spark.default.parallelism。我们认为每个CPU核上并行运行2-3个task是推荐配置。

Memory Usage of Reduce Tasks:
由于你的RDD无法适配空余内存,程序会报OOM。有时候导致这种情况的可能只是你的其中一个数据集。通常的优化方法有增大并行度使得每个分区的输入变小或提供自己的partitioner使得数据更加均匀分布。

Data Locality:
数据本地性会对spark job的性能产生极大影响。如果代码和数据在一起,则计算会变得很快;但如果两者分开了,则其中一方需移动到另一方的进程去执行。一般来说,迁移代码比迁移数据要快。这是Spark构建数据本地性机制的基本原则。

数据本地性可被表示为数据离代码有多近,从近到远可被表示为几个级别:

  • PROCESS_LOCAL 数据在同一个JVM中
  • NODE_LOCAL 数据在同一个结点,比如HDFS的同一个DataNode或同结点另一个executor上。
  • NO_PREF 数据从任何地方访问速度都一样,无任何本地性偏好。
  • RACK_LOCAL 数据在同一个机架上,一般定义即是同一个交换机子网下。
  • ANY 数据不在同一个机架上,可能在网络上。

Spark优先调度tasks都有最佳的本地性,但这不总是有可能做到的。如果有空闲的executor和未处理的数据,Spark会降低数据本地性。此时有两个选择:一是等待直到当前节点cpu释放足够起一个新task去处理同结点数据;二是立即在别的结点起个新task兵移动数据。

通常Spark依然采取第一种,等待cpu空闲在本地起新task。如果等待超时了,才执行第二种方案移动数据。每个级别间的等待超时参数可以统一配置也可以分别配置,参见 spark.locality。如果你的任务的本地性很差并且执行时间较长,你可能需要调大超时时间。一般来说默认配置适用大多数场景。(设1s就行了...没必要多等)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值