Spark调优
因为Spark是内存当中的计算框架,集群中的任何资源都会让它处于瓶颈,CPU、内存、网络带宽。通常,内存足够的情况之下,网络带宽是瓶颈,这时我们就需要进行一些调优,比如用一种序列化的方式来存储RDD来减少内存使用,这边文章就讲两种方式,数据序列化和内存调优,接下来我们会分几个主题来谈论这个调优问题。
1、数据序列化
(1) Spark默认是使用Java的 ObjectOutputStream框架,它支持所有的继承于java.io.Serializable序列化,如果想要进行调优的话,可以通过继承java.io.Externalizable。这种格式比较大,而且速度慢。
(2)Spark还支持这种方式Kryo serialization,它的速度快,而且压缩比高于 Java的序列化,但是它不支持所有的 Serializable格式,并且需要在程序里面注册。它需要在实例化 SparkContext之前进行注册, 下面是它的使用例子:
import com.esotericsoftware.kryo.Kryo
import org.apache.spark.serializer.KryoRegistrator class MyRegistrator extends KryoRegistrator {
override def registerClasses(kryo: Kryo) {
kryo.register(classOf[MyClass1])
kryo.register(classOf[MyClass2])
}
} // Make sure to set these properties *before* creating a SparkContext!
System.setProperty("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
System.setProperty("spark.kryo.registrator", "mypackage.MyRegistrator")
val sc = new SparkContext(...)
如果对象很大,需要设置这个参数 spark.kryoserializer.buffer.mb,默认是2。
想了解更多关于这个格式的,可以查看这个网址https://github.com/EsotericSoftware/kryo
2、内存调化
这里面需要考虑3点,对象使用的内存、访问这些对象的开销、垃圾回收器的管理开销。
通常,对象访问的速度都很快,但是需要2-5x的空间来存储,因为下面的原因:
1)每一个独立的Java对象,都有一个16字节的“ object header”和关于这个对象的信息,比如指针。
2)Java String类型有40字节的“object header”,然后因为 Unicode,每个字符要存储2个字节,这样10个字符要消耗掉大概60个字节。
3)普通的容器类,比如HashMap和LinkedList,它们采用的是链式的数据结构,它需要封装每个实体,不仅需要头信息,还要有个指针指向下一个实体。
4)原始容器类型通常存储它们为装箱类型,比如java.lang.Integer。
下面我们就来讨论如何确定这些对象的内存开销并且如何进行调优,比如改变数据结构或者序列化存储数据。下面我们讲谈论如何调优Spark的Cache大小以及Java的垃圾回收器。
(1)确定内存使用情况
首先我们要确定内存使用情况,确定数据集的内存使用情况,最好的方法就是创建一个RDD,然后缓存它,然后查看日志,日志会记录出来它的每个分片使用的大小,然后我们可以找个这些分片的大小计算出总大小,如下:
INFO BlockManagerMasterActor: Added rdd_0_1 in memory on mbk.local:50311 (size: 717.5 KB, free: 332.3 MB)
(2)数据结构调优
1) 优先使用数组和原生类型来替代容器类,或者使用fastutil找个包提供的容器类型,fastutil的官方链接是http://fastutil.di.unimi.it/。
2)避免大量的小对象的嵌套结构。
3)使用数字的ID来表示,而不是使用字符串的ID。
4)如果内存小于32GB,设置JVM参数 -XX:+UseCompressedOops为4个字节而不是8个字节;在Java7或者之后的,尝试使用 -XX:+UseCompressedStrings存储ASCII字符串8个比特一个字符 。这些参数可以添加到spark-env.sh,根据我的观察,应该是设置到 SPARK_JAVA_OPTS这个参数上。
(3)序列化RDD存储
强烈建议使用Kryo进行序列化,这也是降低内存使用最简单的方式。
(4)垃圾回收器调优
当我们只使用一次RDD的时候,不会存在这方面的问题。当java需要清除旧的对象给新的对象腾出空间的时候,它需要遍历所有对象,然后找出那些没有使用的。这里最中要的一点是记住,垃圾回收器的代价是和它里面的对象的数量相关的。查看GC是不是一个问题,第一件事就是使用序列化的缓存方式。
GC还可以出现的问题就是执行任务所需要的内存大小,下面我们讲讨论如何控制分配给RDD缓存的空间大小来减轻这个问题。
1)确定GC的影响
添加这些参数到 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps到SPARK_JAVA_OPTS这个参数,让它出书GC的信息,然后运行任务。
2)缓存大小调优
影响GC的一个重要配置参数是分配给缓存RDD的内存大小,Spark默认是使用 66%的可配置内存大小(通过 spark.executor.memory or SPARK_MEM来配置 )来存储RDD,也即是说,只有33%是给任务执行过程当中执行过程当中创建的对象的。
当你的程序慢下来,你发现GC很频繁或内存不够等现象,降低它的值会起到一些效果,我们可以通过这个参数 System.setProperty("spark.storage.memoryFraction", "0.5")来达到这个效果。
3)高级内存调优
java的堆内存是分为两个区间,Young和Old,Young是用来存储短生命周期的对象,Old是用来存储长生命周期的对象。 Young又可以进一步细分为 [Eden, Survivor1, Survivor2]。 一个简单的垃圾过程可以描述为:当 Eden满的时候,一个简单的GC会运行在Eden和依赖它的对象, Survivor1被复制到Survivor2。 Survivor区域进行了交换。如果一个对象足够老或者Survivor2满了,它就会被移到Old区。当Old区也满的时候,一个完整的GC就会触发。
Spark里面的GC调优目标是确保RDD存储在Old区间,并且Young区有足够的空间去存储那些短生命周期的对象。这样可以减少完全的GC去回收那些任务执行中的临时对象。 下面的的这些步骤可能是有用的:
1)检查 GC的统计信息,查看在任务执行完成之前是不是执行过多次的GC,这意味着内存不足以执行任务。
2)当Old区快满的时候,我们可以通过调整这个参数 spark.storage.memoryFraction来减少缓存使用的内存量,少缓存一点对象比拖慢作业执行更好一些。
3)当发生了很多次小的GC,而不是重要的GC时候,我们可以考虑多分配点内存给 Eden,假设一个任务需要使用E大小的内存,我们可以分配给Eden的内存大小为: -Xmn=4/3*E,这个大小同样适用于 survivor区间 。
4)当从HDFS上读取数据的时候,任务的所需内存可以估计为block的大小,一个反压缩的块是2-3倍的大小,我们考虑用3-4个任务来执行,这样我们可以考虑设置Eden的大小为4*3*64MB。
3、其它的考虑
(1)并行的水平
建议是1个CPU核心2-3个任务,可以通过程序的函数的时候传入 numPartitions 参数,或者通过系统变量 spark.default.parallelism来改变。
(2)Reduce任务的内存使用情况
有时候出现 OutOfMemoryError并不是因为RDD太大内存装不下,而是因为执行Reduce任务执行的 groupByKey的结果太大。Spark的 shuffle操作( sortByKey , groupByKey , reduceByKey , join , etc)它会为每一个任务建立一个hash表来执行grouping操作,简单的处理方式就是增加并行水平,这样每个任务的输入集变小。Spark能够支持每个任务200ms的速度,因为它在所有任务共享了JVMs,减小了发布任务的开销,所有可以安全的增加并行水平超过核心数。
(3)使用broadcast存储大的变量
使用Spark里面的broadcast的变量来存储大的变量可以大大减少每个序列化任务的大小和集群发布任务的开销。大对象的任务都可以考虑使用broadcast变量,Spark在master上会打印每个序列化任务的大小,当大小超过20KB的时候,可以考虑调优。
4、总结
这里简短的指出了我们调优的时候需要注意的一些重要的点,通常我们把序列化方式调整为 Kryo并且缓存方式改为序列化存储方式就可以解决大部分的问题了。
Spark调优的更多相关文章
- 【Spark学习】Apache Spark调优
Spark版本:1.1.0 本文系以开源中国社区的译文为基础,结合官方文档翻译修订而来,转载请注明以下链接: http://www.cnblogs.com/zhangningbo/p/4117981. ...
- 【Spark调优】提交job资源参数调优
[场景] Spark提交作业job的时候要指定该job可以使用的CPU.内存等资源参数,生产环境中,任务资源分配不足会导致该job执行中断.失败等问题,所以对Spark的job资源参数分配调优非常重要 ...
- 【Spark调优】大表join大表,少数key导致数据倾斜解决方案
[使用场景] 两个RDD进行join的时候,如果数据量都比较大,那么此时可以sample看下两个RDD中的key分布情况.如果出现数据倾斜,是因为其中某一个RDD中的少数几个key的数据量过大,而另一 ...
- 【Spark调优】小表join大表数据倾斜解决方案
[使用场景] 对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中的一个RDD或表的数据量比较小(例如几百MB或者1~2GB),比较适用此方案. [解决方案] ...
- 【Spark调优】数据倾斜及排查
[数据倾斜及调优概述] 大数据分布式计算中一个常见的棘手问题——数据倾斜: 在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或j ...
- 【Spark调优】Broadcast广播变量
[业务场景] 在Spark的统计开发过程中,肯定会遇到类似小维表join大业务表的场景,或者需要在算子函数中使用外部变量的场景(尤其是大变量,比如100M以上的大集合),那么此时应该使用Spark的广 ...
- 【Spark调优】Kryo序列化
[Java序列化与反序列化] Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程.序列化使用场景:1.数据的持久化,通过序列化可以把数据永久 ...
- 【翻译】Spark 调优 (Tuning Spark) 中文版
由于Spark自己的调优guidance已经覆盖了很多很有价值的点,因此这里直接翻译一份过来.也作为一个积累. Spark 调优 (Tuning Spark) 由于大多数Spark计算任务是在内存中运 ...
- 【Spark调优】Shuffle原理理解与参数调优
[生产实践经验] 生产实践中的切身体会是:影响Spark性能的大BOSS就是shuffle,抓住并解决shuffle这个主要原因,事半功倍. [Shuffle原理学习笔记] 1.未经优化的HashSh ...
- 【Spark调优】:结合业务场景,优选高性能算子
聚合操作使用reduceByKey/aggregateByKey替代groupByKey 参见我的这篇博客说明 [Spark调优]:如果实在要shuffle,使用map侧预聚合的算子 内存充足前提下使 ...
随机推荐
- 三十一、【WCF路由中间件】WCFHosting服务主机的路由器与负载均衡和实现思路
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://pan.baid ...
- easyui textbox event 添加
$('#tt').textbox({ inputEvents:$.extend({},$.fn.textbox.defaults.inputEvents,{ keyup:function(e){ co ...
- SNF开发平台WinForm之十-Excel导入-SNF快速开发平台3.3-Spring.Net.Framework
7.1运行效果: 2.Excel导入开发实现 2.1. 创建窗体,修改命名空间 新增的窗体命名“FrmImport表名”,这个导入窗口比较其它窗口会特殊一些,需要继承BaseFormImport父级窗 ...
- 记一个dynamic的坑
创建一个控制台程序和一个类库, 在控制台创建一个匿名对象,然后再在类库中访问它,代码如下: namespace ConsoleApplication1 { class Program { static ...
- 手把手教你搭建LyncServer2013之部署及配置监控功能(十八)
自弃用监控服务器角色以来,已对 Microsoft Lync Server 2013 监控基础结构进行了重大更改.不再采用不同的监控服务器角色(通常需要组织设置专用计算机来充当监控服务器),现在监控服 ...
- codeforces B. Design Tutorial: Learn from Life
题意:有一个电梯,每一个人都想乘电梯到达自己想要到达的楼层!从a层到b层的时间是|a-b|, 乘客上下电梯的时间忽略不计!问最少需要多少的时间.... 这是一道神题啊,自己的思路不知不觉的就按 ...
- Python单元测试框架之pytest -- 断言
对于测试来讲,不管是功能测试,自动化测试,还是单元测试.一般都会预设一个正确的预期结果,而在测试执行的过程中会得到一个实际的结果.测试的成功与否就是拿实际的结果与预期的结果进行比较.这个比的过程实际就 ...
- 使用 CSS3 打造一组质感细腻丝滑的按钮
CSS3 引入了众多供功能强大的新特性,让设计和开发人员能够轻松的创作出各种精美的界面效果.下面这些发出闪亮光泽的按钮,很漂亮吧?把鼠标悬停在按钮上,还有动感的光泽移动效果. 温馨提示:为保证最佳的效 ...
- 免费下载!Twitter Bootstrap V3 矢量界面素材
Bootstrap 3 Vector UI Kit 包含所有矢量格式的 Twitter Bootstrap 3 界面控制元素.Glyphicons 以及额外的一些界面素材,而且基本的图形元素都切好图了 ...
- Python文件操作详解
Python内置了一个open()方法,用于对本地文件进行读写操作.这个功能简单.实用,属于必须掌握的基础知识. 使用open方法操作文件可以分三步走,一是打开文件,二是操作文件,三是关闭文件.下面分 ...