在Spark应用开发中,很容易出现如下报错:

org.apache.spark.SparkException: Task not serializable
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:304)
at org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:294)
at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:122)
at org.apache.spark.SparkContext.clean(SparkContext.scala:2058)
...
Caused by: java.io.NotSerializableException

该报错意思是用户代码的transformation操作中包含不可序列化的对象引用。

本文主要从以下三个方面解释Spark 应用中序列化问题 。 
1、Java序列化含义? 
2、Spark代码为什么需要序列化? 
3、如何解决Spark序列化问题?

1、Java序列化含义?

Spark是基于JVM运行的进行,其序列化必然遵守Java的序列化规则。

序列化就是指将一个对象转化为二进制的byte流(注意,不是bit流),然后以文件的方式进行保存或通过网络传输,等待被反序列化读取出来。序列化常被用于数据存取和通信过程中。

对于java应用实现序列化一般方法:

  • class实现序列化操作是让class 实现Serializable接口,但实现该接口不保证该class一定可以序列化,因为序列化必须保证该class引用的所有属性可以序列化。

  • 这里需要明白,static和transient修饰的变量不会被序列化,这也是解决序列化问题的方法之一,让不能序列化的引用用static和transient来修饰。(static修饰的是类的状态,而不是对象状态,所以不存在序列化问题。transient修饰的变量,是不会被序列化到文件中,在被反序列化后,transient变量的值被设为初始值,如int是0,对象是null)

  • 此外还可以实现readObject()方法和writeObject()方法来自定义实现序列化。(具体用例见参考链接)

2、Spark的transformation操作为什么需要序列化?

Spark是分布式执行引擎,其核心抽象是弹性分布式数据集RDD,其代表了分布在不同节点的数据。Spark的计算是在executor上分布式执行的,故用户开发的关于RDD的map,flatMap,reduceByKey等transformation 操作(闭包)有如下执行过程: 
1. 代码中对象在driver本地序列化 
2. 对象序列化后传输到远程executor节点 
3. 远程executor节点反序列化对象 
4. 最终远程节点执行 
故对象在执行中需要序列化通过网络传输,则必须经过序列化过程。

3、如何解决Spark序列化问题?

如果出现NotSerializableException报错,可以在spark-default.xml文件中加入如下参数来开启SerializationDebugger功能类,从而可以在日志中打印出序列化出问题的类和属性信息。

spark.executor.extraJavaOptions  -Dsun.io.serialization.extendedDebugInfo=true
spark.driver.extraJavaOption -Dsun.io.serialization.extendedDebugInfo=true

对于scala语言开发,解决序列化问题主要如下几点:

  • 在Object中声明对象 (每个class对应有一个Object)
  • 如果在闭包中使用SparkContext或者SqlContext,建议使用SparkContext.get() and SQLContext.getActiveOrCreate()
  • 使用static或transient修饰不可序列化的属性从而避免序列化。 
    注:scala语言中,class的Object

对于java语言开发,对于不可序列化对象,如果本身不需要存储或传输,则可使用static或trarnsient修饰;如果需要存储传输,则实现writeObject()/readObject()使用自定义序列化方法。

此外注意

对于Spark Streaming作业,注意哪些操作在driver,哪些操作在executor。因为在driver端(foreachRDD)实例化的对象,很可能不能在foreach中运行,因为对象不能从driver序列化传递到executor端(有些对象有TCP链接,一定不可以序列化)。所以这里一般在foreachPartitions或foreach算子中来实例化对象,这样对象在executor端实例化,没有从driver传输到executor的过程。

dstream.foreachRDD { rdd =>
val where1 = "on the driver"
rdd.foreach { record =>
val where2 = "on different executors"
}
}
}

参考资料: 
Avoid NotSerializable Error in Spark Job 
spark not serializable problem 
Spark Streaming / Tips on Running Streaming Apps inside Databricks 
Java 序列化的高级认识 
什么是writeObject 和readObject?可定制的序列化过程

Spark 序列化问题的更多相关文章

  1. spark序列化及MapOutputTracker解析

    本文主要打算对spark内部的序列化机制以及在shuffle map中起衔接作用的MapOutputTracker做一下剖析.主要涉及具体实现原理以及宏观设计的一些思路. 1,spark序列化 任何一 ...

  2. spark系列-4、spark序列化方案、GC对spark性能的影响

    一.spark的序列化 1.1.官网解释 http://spark.apache.org/docs/2.1.1/tuning.html#data-serialization 序列化在任何分布式应用程序 ...

  3. 在Spark中使用Kryo序列化

    spark序列化  对于优化<网络性能>极为重要,将RDD以序列化格式来保存减少内存占用. spark.serializer=org.apache.spark.serializer.Jav ...

  4. 【Spark调优】Kryo序列化

    [Java序列化与反序列化] Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程.序列化使用场景:1.数据的持久化,通过序列化可以把数据永久 ...

  5. Spark性能优化(1)——序列化、内存、并行度、数据存储格式、Shuffle

    序列化 背景: 在以下过程中,需要对数据进行序列化: shuffling data时需要通过网络传输数据 RDD序列化到磁盘时 性能优化点: Spark默认的序列化类型是Java序列化.Java序列化 ...

  6. Hadoop的Writerable在Spark无法序列化的问题

    Spark序列化这块网上讲的比较少,自己还没来得及看这块代码,今天编程的时候遇到一个Hadoop的Writerable实现在Spark无法序列化的问题.我的代码如下: object EntryApp ...

  7. 浅谈Spark Kryo serialization

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3833985.html 最近在使用spark开发过程中发现当数据量很大时,如果cache数据将消耗很多的内 ...

  8. Spark调优与调试

    1.使用SparkConf配置Spark (1)在java中使用SparkConf创建一个应用: SparkConf conf =;i++){ javaBean bean =new javaBean( ...

  9. Spark生态以及原理

    spark 生态及运行原理 Spark 特点 运行速度快 => Spark拥有DAG执行引擎,支持在内存中对数据进行迭代计算.官方提供的数据表明,如果数据由磁盘读取,速度是Hadoop MapR ...

随机推荐

  1. 【jQuery】jQuery与Ajax的应用

    1.demo1 <script language="javascript" type="text/javascript"> //通过这个函数来异步获 ...

  2. python之使用__future__

    Python的新版本会引入一些新的功能特性,但一般一部分的新功能可以在旧版本上测试,测试成功再移植到新的版本上,旧版本可以通过导入__future__模块的某些功能,测试新版本的新功能.(注意:fut ...

  3. SpringBoot实战(九)之Validator

    表单验证,是最为常见的,今天演示的是利用hibernate-validtor进行校验,有的时候,虽然前端方面通过jQuery或者require.js校验框架进行校验,可以减轻服务器的压力和改善用户体验 ...

  4. Samba服务器的配置与使用

    1.系统环境变量 Fedora: yum install libacl-devel libblkid-devel gnutls-devel \ readline-devel python-devel ...

  5. PAT——1057. 数零壹

    给定一串长度不超过105的字符串,本题要求你将其中所有英文字母的序号(字母a-z对应序号1-26,不分大小写)相加,得到整数N,然后再分析一下N的二进制表示中有多少0.多少1.例如给定字符串“PAT ...

  6. 学习VCL之路(1)

    在TObject类中,有一个Dispatch()方法和一个DefaultHandler()方法,它们都是与消息分发机制相关的. Dispatch()负责将特定的消息分发给合适的消息处理函数.首先它会在 ...

  7. ASP.NET Core MVC中Controller的Action如何直接使用Response.Body的Stream流输出数据

    在ASP.NET Core MVC中,我们有时候需要在Controller的Action中直接输出数据到Response.Body这个Stream流中,例如如果我们要输出一个很大的文件到客户端浏览器让 ...

  8. Linux环境下部署SpringBoot项目

    1.在pom文件中添加maven插件 <build> <plugins> <plugin> <groupid>org.springframework.b ...

  9. 查看mysql的安装目录

    如果忘记了MySQL的安装目录,怎么快速找到呢?方法或许很多,作者觉得这种最方便了 环境:windows+mysql+navicat 方法:进入mysql命令行输入:show variables li ...

  10. 【leetcode】804

    import java.util.*; import java.lang.*; public class Test{ public static int fun_solve(String[] word ...