在Spark中内置支持两种系列化格式:(1)、Java serialization;(2)、Kryo serialization。在默认情况下,Spark使用的是Java的ObjectOutputStream系列化框架,它支持所有继承java.io.Serializable的类系列化,虽然Java系列化非常灵活,但是它的性能不佳。然而我们可以使用Kryo 库来系列化,它相比Java serialization系列化高效,速度很快(通常比Java快10x),但是它不支持所有的系列化对象,而且要求用户注册类。
在Spark中,使用Kryo系列化比使用Java系列化更明智。在shuffling和caching大量数据的情况下,使用 Kryo系列化就变得非常重要。
虽然Kryo支持对RDD的cache和shuffle,但是在Spark中不是内置就显示提供使用Kryo将数据系列化到磁盘中的输入输出API,RDD中的saveAsObjectFile和SparkContext中的objectFile方法仅仅支持使用Java系列化。所以如果我们可以使用Kryo系列化将会变得很棒!
在这篇文章中,我将讨论如何自定义Kryo系列化输出输出相关API来将数据进行读写到磁盘中。
写数据
通常,我们使用rdd.saveAsObjectFile API将已经系列化的对象写入到磁盘中。下面的代码将展示如何使用我们自定义的saveAsObjectFile方法将已经使用kryo系列化的对象写入到磁盘中:
1 |
def saveAsObjectFile[T: ClassTag](rdd: RDD[T], path: String) |
这个函数中参数rdd就是我们需要写的数据;path是数据保存的路径。
1 |
val kryoSerializer = new KryoSerializer(rdd.context.getConf) |
KryoSerializer是Spark内部提供的用于提供操作Kryo的类。在上述代码中,我们创建了KryoSerializer对象,并从rdd.context.getConf中获取传进来的缓存大小。
1 |
rdd.mapPartitions(iter => iter.grouped(10) |
所有的objectFile 将会在HDFS上保存,我们对RDD中的每个分片进行遍历,然后将他们转换成Byte数组。
1 |
val kryo = kryoSerializer.newKryo() |
对每个splitArray,我们首先创建了kryo实例,kryo是线程不安全的,所以我们在每个map操作中单独创建。当我们调用 kryoSerializer.newKryo()来创建新的kryo实例,他也会调用我们自定义的KryoRegistrator。
1 |
//create output stream and plug it to the kryo output |
2 |
val bao = new ByteArrayOutputStream() |
3 |
val output = kryoSerializer.newKryoOutput() |
4 |
output.setOutputStream(bao) |
5 |
kryo.writeClassAndObject(output, splitArray) |
一旦我们拥有kryo实例,我们就可以创建kryo输出对象,然后我们将类信息和对象写入到那个输出对象中。
1 |
val byteWritable = new BytesWritable(bao.toByteArray) |
2 |
(NullWritable.get(), byteWritable) |
3 |
}).saveAsSequenceFile(path) |
我们在创建byteWritable的时候,包装了bytearray,然后保存成Sequence文件。使用那些代码我们就可以将Kryo对象写入到磁盘中。完整代码如下:
07 |
* 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货 |
08 |
* 过往记忆博客微信公共帐号:iteblog_hadoop |
11 |
def saveAsObjectFile[T: ClassTag](rdd: RDD[T], path: String) { |
12 |
val kryoSerializer = new KryoSerializer(rdd.context.getConf) |
14 |
rdd.mapPartitions(iter => iter.grouped(10) |
17 |
//initializes kyro and calls your registrator class |
18 |
val kryo = kryoSerializer.newKryo() |
20 |
//convert data to bytes |
21 |
val bao = new ByteArrayOutputStream() |
22 |
val output = kryoSerializer.newKryoOutput() |
23 |
output.setOutputStream(bao) |
24 |
kryo.writeClassAndObject(output, splitArray) |
27 |
// We are ignoring key field of sequence file |
28 |
val byteWritable = new BytesWritable(bao.toByteArray) |
29 |
(NullWritable.get(), byteWritable) |
30 |
}).saveAsSequenceFile(path) |
读数据
光有写没有读对我们来说仍然不完美。通常我们使用sparkContext中的objectFile API从磁盘中读取数据,这里我们使用自定义的objectFile API来读取Kryo对象文件。
01 |
def objectFile[T](sc: SparkContext, path: String, minPartitions: Int = 1) |
02 |
(implicit ct: ClassTag[T]) = { |
03 |
val kryoSerializer = new KryoSerializer(sc.getConf) |
04 |
sc.sequenceFile(path, classOf[NullWritable], classOf[BytesWritable], |
07 |
val kryo = kryoSerializer.newKryo() |
08 |
val input = new Input() |
09 |
input.setBuffer(x._2.getBytes) |
10 |
val data = kryo.readClassAndObject(input) |
11 |
val dataObject = data.asInstanceOf[Array[T]] |
上面的步骤和写的步骤很类似,只不过这里我们使用的是input,而不是output。我们从BytesWritable中读取bytes数据,然后使用readClassAndObject API反序列化数据。
如何使用
下面例子使用上面介绍的两个方法来系列化和反序列化Person对象:
07 |
* 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货 |
08 |
* 过往记忆博客微信公共帐号:iteblog_hadoop |
11 |
// user defined class that need to serialized |
12 |
class Person(val name: String) |
14 |
def main(args: Array[String]) { |
16 |
if (args.length < 1) { |
17 |
println("Please provide output path") |
20 |
val outputPath = args(0) |
22 |
val conf = new SparkConf().setMaster("local").setAppName("kryoexample") |
23 |
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") |
24 |
val sc = new SparkContext(conf) |
26 |
//create some dummy data |
27 |
val personList = 1 to 10000 map (value => new Person(value + "")) |
28 |
val personRDD = sc.makeRDD(personList) |
30 |
saveAsObjectFile(personRDD, outputPath) |
31 |
val rdd = objectFile[Person](sc, outputPath) |
32 |
println(rdd.map(person => person.name).collect().toList) |
- Spark:将RDD[List[String,List[Person]]]中的List[Person]通过spark api保存为hdfs文件时一直出现not serializable task,没办法找到"spark自定义Kryo序列化输入输出API"
声明:本文转自<在Spark中自定义Kryo序列化输入输出API> 在Spark中内置支持两种系列化格式:(1).Java serialization:(2).Kryo seriali ...
- 在Spark中使用Kryo序列化
spark序列化 对于优化<网络性能>极为重要,将RDD以序列化格式来保存减少内存占用. spark.serializer=org.apache.spark.serializer.Jav ...
- Spark中持久化和序列化学习
一.cache和persisit的对比 -rw-r--r--@ 1 hadoop staff 68M 5 17 07:04 access.log    cache/persitence是 laz ...
- Spark中自定义累加器
通过继承AccumulatorV2可以实现自定义累加器. 官方案例可参考:http://spark.apache.org/docs/latest/rdd-programming-guide.html# ...
- jackson中自定义处理序列化和反序列化
http://jackyrong.iteye.com/blog/2005323 ********************************************** 对于一直用gson的人来说 ...
- Spark中自定义累加器Accumulator
1. 自定义累加器 自定义累加器需要继承AccumulatorParam,实现addInPlace和zero方法. 例1:实现Long类型的累加器 object LongAccumulatorPara ...
- Spark 中的机器学习库及示例
MLlib 是 Spark 的机器学习库,旨在简化机器学习的工程实践工作,并方便扩展到更大规模.MLlib 由一些通用的学习算法和工具组成,包括分类.回归.聚类.协同过滤.降维等,同时还包括底层的优化 ...
- 【Spark调优】Kryo序列化
[Java序列化与反序列化] Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程.序列化使用场景:1.数据的持久化,通过序列化可以把数据永久 ...
- spark 中的RDD编程 -以下基于Java api
1.RDD介绍: RDD,弹性分布式数据集,即分布式的元素集合.在spark中,对所有数据的操作不外乎是创建RDD.转化已有的RDD以及调用RDD操作进行求值.在这一切的背后,Spark会自动 ...
随机推荐
- day2 购物商城
购物商城 商品展示.价格 买,加入购物车 付款,钱不够.(减商品,充值)
- ceph笔记(一)
一.ceph概述本质上是rados:可靠的.自动的.分布式对象存储特性:高效性(大型的网络raid,性能无限接近raid).统一性(支持文件存储.块存储.对象存储).可扩展性数据库的一个弱点:查表ce ...
- Python全栈开发之7、模块和几种常见模块以及format知识补充
一.模块的分类 Python流行的一个原因就是因为它的第三方模块数量巨大,我们编写代码不必从零开始重新造轮子,许多要用的功能都已经写好封装成库了,我们只要直接调用即可,模块分为内建模块.自定义的模块. ...
- VuGen录制选项Recording Options
- 最大公约数or最小公倍数
最大公约数or最小公倍数 import org.junit.Test; public class 最大公约数or最小公倍数 { public int maxGYS(int m,int n) { int ...
- 【ASP.NET】:Ckeditor+Fckeditor的使用
首先这三个文件:下载ckeditor和ckeditor_aspnet_3.6.4和ckfinder 然后把这三个文件复制到项目根目录下 添加引用CKEditor.NET.dll CKFind ...
- thinkphp5.0配置加载
ThinkPHP支持多种格式的配置格式,但最终都是解析为PHP数组的方式. PHP数组定义 返回PHP数组的方式是默认的配置定义格式,例如: //项目配置文件 return [ // 默认模块名 'd ...
- C++ 四种显示转换
转自:http://www.jellythink.com/archives/205 (果冻想) 前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中 ...
- http request GET 乱码分析
提交一个GET请求 在浏览器地址栏或搜索框输入地址:http://www.baidu.com/content/衣服?keyword=衬衣 其中的中文会被浏览器进行编码,具体编码情况请参考阮大神:关于U ...
- Arduino可穿戴教程之第一个程序——连接硬件选择板子(二)
Arduino可穿戴教程之第一个程序——连接硬件选择板子(二) 2.4.2 连接硬件 在选择好示例程序后就可以将LilyPad通过LilyPad编程器连接到电脑了. 2.4.3 选择板子 如果你了 ...