spark优化指南

Spark 程序可能由集群中的任何资源( CPU ,网络带宽或内存)导致瓶颈。首先我们先来介绍了一下spark内存管理的基本原理。后面介绍了内存调优的几种方法。


1. 内存管理概述

Spark中的内存使用大部分属于两类:执行和存储。 执行内存是指用于在混洗,连接,排序和聚合中进行计算的内存,而存储内存指的是用于跨群集缓存和传播内部数据的内存。 在Spark中,执行内存和存储内存共享统一区域(M)。 当不使用执行内存时,存储可以获取所有可用内存,反之亦然。 如有必要,执行内存可能会挤占存储内存空间,但只能在总存储内存使用量低于特定阈值(R)时才执行。 换句话说,R描述了M中的一个子区域,其中缓存块空间不会被挤占。 由于执行的复杂性,存储不会挤占执行内存空间。


2. 内存调优

在调整内存使用情况时有三个注意事项:对象使用的内存量(您可能希望整个数据集适合内存),访问这些对象的成本以及垃圾收集的开销。我们可以使用下面的几种方法来对内存进行优化。

2.1 调整数据结构

减少内存消耗的第一种方法是避免增加开销的Java功能,例如基于指针的数据结构和包装对象。

2.2序列化RDD存储

减少内存使用量的一种更简单的方法是以序列化的形式存储它们。以序列化格式存储数据的唯一缺点是访问时间较慢,这是由于必须对每个对象进行反序列化。 如果你想以序列化的形式缓存数据,我们强烈推荐使用Kryo,因为它比Java序列化(当然也比原始的Java对象)要小得多。

2.2.1 数据序列化

spark提供了两种序列化库:
1. Java serialization: 默认情况下,Spark使用Java的ObjectOutputStream框架来序列化对象。
2. Kryo serialization:Spark还可以使用Kryo库(版本2)更快地序列化对象。 Kryo比Java序列化速度更快且更紧凑(通常高达10倍),但不支持所有的Serializable类型,并且需要事先注册您将在程序中使用的类以获得最佳性能。建议在任何网络密集型应用程序中尝试使用它。通过调用conf.set(“spark.serializer”,“org.apache.spark.serializer.KryoSerializer”)来切换到Kryo。可以使用 registerKryoClasses 方法来注册自己的自定义类,例如:

val conf = new SparkConf().setMaster(...).setAppName(...)
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
val sc = new SparkContext(conf)

2.3 垃圾收集(GC)调整

垃圾收集( garbage collection)的成本与Java对象的数量成正比,因此使用较少对象的数据结构会大大降低此成本。

2.4 其他需要注意的地方

2.4.1 并行度水平

一般来说,我们建议您的群集中每个CPU内核有2-3个任务。

2.4.2 广播大的变量

使用SparkContext中可用的广播功能可以大大减少每个序列化任务的大小和通过群集启动作业的成本。 如果您的任务使用其内部驱动程序中的任何大对象,请考虑将其转换为广播变量。

2.4.3 数据本地化

如果数据和运行在其上的代码在一起,那么计算就会很快。 但是,如果代码和数据是分开的,就必须转移一个到另一个上。 通常,由于代码大小比数据小得多,因此将序列化代码从一个地方运送到另一个地方比一个数据块的移动要更快。


END

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页