hadoop深入研究:(十三)——序列化框架
Mapreduce之序列化框架(转自http://blog.csdn.net/lastsweetop/article/details/9376495)
框架简介
大部分的MapReduce程序都使用Writable键–值对作为输入和输出,但这并不是Hadoop强制使用的,其他序列化机制也能和Hadoop配合,并应用于MapReduce中。
目前,除了前面介绍过的Java序列化机制和Hadoop使用的Writable机制,还流行其他序列化框架,如Hadoop Avro、Apache Thrift和Google Protocol Buffer。
MapReduce仅仅可以支持Writable做key,value吗?答案是否定的。事实上,可以使用任何类型:只要能有一种机制能对每个类型进行类型与二进制表示的来回转换。为此Hadoop提供了一个针对序列化做替换的框架来支持,他们在org.apache.hadoop.io.serializer包中,Writable可以作为MapReduce支持的类型也是因为实现了这个框架,类不多,我们从几个接口说起。
Hadoop提供了一个简单的序列化框架API,用于集成各种序列化实现,该框架由Serialization实现(在org.apache.hadoop.io.serializer包中)。
Serialization是一个接口,使用抽象工厂的设计模式.定义了一组接口,判断是否支持输入的类,根据输入的类给出序列化接口和反序列化接口
/**
*
* 包装一个序列化/反序列化对 (抽象工厂类)*/public interface Serialization<T> {
/**
* 允许客户端进行测试:给的序列化是否支持给定的类 */
boolean accept(Class<?> c);
/**
* 获得用于序列化对象的Serializer实现 */
Serializer<T> getSerializer(Class<T> c);
/**
* 获得用于反序列化对象的Deserializer实现*/
Deserializer<T> getDeserializer(Class<T> c);
}
参考了:Hadoop的简单序列化框架 - cjt1991 - 博客园 - http://www.cnblogs.com/java-cjt/p/4443852.html
Serializer 定义了一组接口,打开流,序列化,关闭流
如果需要使用Serializer来执行序列化,一般需要通过Open方法来打开Serializer,open()方法传入一个底层的流对象,然后就可以使用serializer()方法序列化对象对底层的流中。最后序列化结束时,通过close()方法关闭Serializer。
public interface Serializer <T> {
void open(java.io.OutputStream outputStream) throws java.io.IOException;
void serialize(T t) throws java.io.IOException;
void close() throws java.io.IOException;
}
Deserializer
定义了一组接口,打开流,反序列化,关闭流
public interface Deserializer <T> {
void open(java.io.InputStream inputStream) throws java.io.IOException;
T deserialize(T t) throws java.io.IOException;
void close() throws java.io.IOException;
}
WritableSerialization
如果你想自己定义一个类似Writable这样的框架,那么你首先需要的就是实现上面三个接口,那么我们先来看下Writable是如何实现的。
public class WritableSerialization extends Configured
implements Serialization<Writable> {
static class WritableDeserializer extends Configured
implements Deserializer<Writable> {
private Class<?> writableClass;
private DataInputStream dataIn;
public WritableDeserializer(Configuration conf, Class<?> c) {
setConf(conf);
this.writableClass = c;
}
public void open(InputStream in) {
if (in instanceof DataInputStream) {
dataIn = (DataInputStream) in;
} else {
dataIn = new DataInputStream(in);
}
}
public Writable deserialize(Writable w) throws IOException {
Writable writable;
if (w == null) {
writable
= (Writable) ReflectionUtils.newInstance(writableClass, getConf());
} else {
writable = w;
}
writable.readFields(dataIn);
return writable;
}
public void close() throws IOException {
dataIn.close();
}
}
static class WritableSerializer implements Serializer<Writable> {
private DataOutputStream dataOut;
public void open(OutputStream out) {
if (out instanceof DataOutputStream) {
dataOut = (DataOutputStream) out;
} else {
dataOut = new DataOutputStream(out);
}
}
public void serialize(Writable w) throws IOException {
w.write(dataOut);
}
public void close() throws IOException {
dataOut.close();
}
}
public boolean accept(Class<?> c) {
return Writable.class.isAssignableFrom(c);
}
public Deserializer<Writable> getDeserializer(Class<Writable> c) {
return new WritableDeserializer(getConf(), c);
}
public Serializer<Writable> getSerializer(Class<Writable> c) {
return new WritableSerializer();
}
}
两个内部静态类分别实现Serializer和Deserializer接口,然后getSerializer和getDeserializer分别实例化WritableSerializer和WritableDeserializer,
accept方法仅仅是判断输入类是否是Writable的子类。
通过"io.serializations"指定以实现Serialization,各个类之间通过逗号隔开,默认的Serialization有WritableSerialization和Avro中Serialization,
这也就是说默认情况下,只有Writable和Avro里的对象可以在MapReduce中使用。
那么你可能有疑问了,hadoop是如何知道一个类该交给哪个Serialization呢,答案也在这个包中,请看
SerializationFactory
先看他的构造器
[java] view plain copy
public SerializationFactory(Configuration conf) {
super(conf);
for (String serializerName : conf.getStrings("io.serializations", new String[]{"org.apache.hadoop.io.serializer.WritableSerialization"})) {
add(conf, serializerName);
}
}
可知他是从"io.serializations"属性指定的实现了Serialization的类,然后再看他是如何知道选哪个Serialization的
[java] view plain copy
public <T> Serialization<T> getSerialization(Class<T> c) {
for (Serialization serialization : serializations) {
if (serialization.accept(c)) {
return (Serialization<T>) serialization;
}
}
return null;
}
好吧,就是这么简单,判断一下是否是对应的子类而已。
这个包里还实现了JavaSerialization,其实就是Java对象的序列化,很多人觉得,这个好简单的,我只要实现java中的序列化接口就可以了,
不用那么费事搞什么Writable和Avro,但是,千万别这么想,非常不推荐使用java对象的序列化,并且详尽的解释为什么不推荐:
Hadoop目前支持两个Serialization实现分别是支持Writable机制的WritableSerialization和支持Java序列化的JavaSerialization。通过JavaSerialization可以在MapReduce程序中方便的使用java类型,如int或String,但Java的ObjectSerialization不如Hadoop的序列化机制有效,非特殊情况不要尝试
为什么不使用java序列化
1.Java序列化不够灵活,为了更好的控制序列化的整个流程所以使用Writable
2.java序列化不符合序列化的标准,没有做一定的压缩,java序列化首先写类名,然后再是整个类的数据,而且成员对象在序列化中只存引用,成员对象的可以出现的位置很随机,既可以在序列化的对象前,也可以在其后面,这样就对随机访问造成影响,一旦出错,整个后面的序列化就会全部错误,但是
Writable完美的弥补了这一点,因为Writable中每一条纪录间是相互独立的
3.Java序列化每次序列化都要重新创建对象,内存消耗大,而Writable是可以重用的。
Hadoop序列化机制的特征
紧凑:由于带宽是Hadoop集群中最稀缺的资源,一个紧凑的序列化机制可以充分利用数据中心的带宽。
快速:在进程间通信(包括MapReduce过程中涉及的数据交互)时会大量使用序列化机制;因此,必须尽量减少序列化和反序列化的开销。
可扩展:随着系统的发展,系统间通信的协议会升级,类的定义会发生变化 ,序列化机制需要支持这些升级和变化。
可操作:可以支持不同开发语言的通信:如C++和Java间的通信。这样的通信,可以通过文件 (需要精心设计文件的格式)或者后者介绍的IPC机制实现。
Java序列化在Hadoop中不适应原因:占用存储空间大,在反序列化中不断创建大量新对象,而Hadoop反序列化可以重用对象,在已有对象上进行反序列化操作。来源: http://blog.sina.com.cn/s/blog_7ed002b30101j6pa.html
序列化IDL
为了和其他语言交互,必须定义序列化的IDL,原先定义的IDL在org.apache.hadoop.record包里,但是后来一直没用起来就淘汰掉了,现在比较常用的就是Avro,后面我们会重点着墨讲解。
Apache的Thrift和Google的Protocol Buffer也是比较流行的序列化框架,但是在Hadoop里使用是有限的,只用于RPC和数据交互,不过有一个开源项目elephant-bird可以把他们使用在MapReduce上。
总结:
A 默认序列化框架是 Writable接口, 缺点: 缺乏语言的可移植性
B 不使用java Serialization, 缺点: 不够精简, 用起来非常纠结, 无法做到 精简,快速, 可扩展, 支持互操作
C Apache Thrift 一般用来作为二进制 数据的永久存储格式, Mapreduce格式对该类的支持有限
D Google Protocol框架 一般用来做二进制数据的永久存储格式,Mapreduce格式对该类的支持有限
E: Avro 更加有生命力, 与编程语言无关, 非常使用hadoop的大规模数据处理。
Avro模式议案使用JSON来写, 数据通常采用二进制格式来编码
和其他序列化类库想比, Avro的性能更好。
=======================================================================================
hadoop权威指南 第三版 page 127
原文:hadoop序列化框架 - qiezikuaichuan的专栏 - CSDN博客 - http://blog.csdn.net/qiezikuaichuan/article/details/48676181
参考:
hadoop深入研究:(十三)——序列化框架 - 独自登高楼 望断天涯路 - CSDN博客 - http://blog.csdn.net/lastsweetop/article/details/9376495#t5
通俗 Python 设计模式——工厂模式 - 知乎专栏 - https://zhuanlan.zhihu.com/p/23803353
抽象工厂模式和工厂模式的区别? - 知乎 - https://www.zhihu.com/question/20367734
抽象工厂模式 - cbf4life - 博客园 - http://www.cnblogs.com/cbf4life/archive/2009/12/23/1630612.html
《JAVA与模式》之抽象工厂模式 - java_my_life - 博客园 - http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
设计模式系列 - 抽象工厂模式 - 后端 - 掘金 - https://juejin.im/entry/58ddc44a8d6d8100613ee7d0
Java 的 23 种设计模式全解析 - 后端 - 掘金 - https://juejin.im/entry/58faca0a1b69e600588cd952
java-设计模式之-抽象工厂模式 | 戒修-沉迷技术的小沙弥 - https://leokongwq.github.io/2016/11/26/java-DesignPatterns-abstractFactory.html
hadoop深入研究:(十三)——序列化框架的更多相关文章
- 5.3.4 Hadoop序列化框架
序列化框架 除了writable实现序列化之外,只要实现让类型和二进制流相互转换,都可以作为hadoop的序列化类型,为此Hadoop提供了一个序列化框架接口,他们在org.apache.hadoop ...
- Mapreduce之序列化框架(转自http://blog.csdn.net/lastsweetop/article/details/9376495)
框架简介 MapReduce仅仅可以支持Writable做key,value吗?答案是否定的.事实上,一切类型都是支持的,只需满足一个小小的条件:每个类型是以二进制流的形式传输.为此Hadoop提供了 ...
- Hadoop的简单序列化框架
Hadoop提供了一个加单的序列化框架API,用于集成各种序列化实现.该框架由Serialization实现. 其中Serialization是一个接口,使用抽象工厂的设计模式,提供了一系列和序列化相 ...
- 为什么hadoop中用到的序列化不是java的serilaziable接口去序列化而是使用Writable序列化框架
继上一个模块之后,此次分析的内容是来到了Hadoop IO相关的模块了,IO系统的模块可谓是一个比较大的模块,在Hadoop Common中的io,主要包括2个大的子模块构成,1个是以Writable ...
- [java]序列化框架性能对比(kryo、hessian、java、protostuff)
序列化框架性能对比(kryo.hessian.java.protostuff) 简介: 优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Pro ...
- 二进制序列化框架easypack发布啦!
简介 easypack是基于boost.serialization的二进制序列化框架,使用极其方便. Examples 基本类型 int age = 20; std::string name = &q ...
- hadoop深入研究:(五)——Archives
转载请注明来源地址:http://blog.csdn.net/lastsweetop/article/details/9123155 简介 我们在hadoop深入研究:(一)——hdfs介绍里已讲过, ...
- hadoop深入研究:(七)——压缩
转载请标明出处:hadoop深入研究:(七)——压缩 文件压缩主要有两个好处,一是减少了存储文件所占空间,另一个就是为数据传输提速.在hadoop大数据的背景下,这两点尤为重要,那么我现在就先来了解下 ...
- Java序列化框架性能比較
博客: http://colobu.com jvm-serializers提供了一个非常好的比較各种Java序列化的的測试套件. 它罗列了各种序列化框架. 能够自己主动生成測试报告. 我在AWS c3 ...
随机推荐
- php-fpm开启报错-ERROR: An another FPM instance seems to already listen on /tmp/php-cgi.sock
在升级了php7.2.0版本之后,重新启动php-fpm过程中遇到一个报错. An another FPM instance seems to already listen on /tmp/php-c ...
- 六.__FILE__ , __LINE__ 与调试日志
很多人可能不知道,C\C++编译器提供了一套针对代码文件的宏定义,它们能够帮助开发者更好的定位代码的BUG. __FILE__ 该宏定义是一个字符串,存储着当前代码文件的完整路径 __LINE__ 该 ...
- awk处理nmap扫描结果
接到个任务,要对大量的主机ip进行扫描: 扫描加过滤脚本贴到底下 #!/bin/bash ### use nmap scan aliyun echo "********Start scan* ...
- 2018-2019-1 20189215《Linux内核原理与分析》第三周作业
<庖丁解牛>第二章书本知识总结 函数调用框架 call指令有两个作用: (1) 将CS:EIP中下一条指令的地址A保存在栈顶: (2)设置CS:EIP指向被调用程序的第一行. ret指令在 ...
- HDU 6342 Expression in Memories(模拟)多校题解
题意:给你一个规则,问你写的对不对. 思路:规则大概概括为:不能出现前导零,符号两边必须是合法数字.我们先把所有问号改好,再去判断现在是否合法,这样判断比一边改一边判断容易想. 下面的讲解问号只改为+ ...
- js的原型继承
<script> //动物(Animal),有头这个属性,eat方法 //名字这个属性 //猫有名字属性,继承Animal,抓老鼠方法 function Animal(name){ thi ...
- C++网络通信字节序问题
htonl(), ntohl(), htons(), ntohs() 函数 在C/C++写网络程序的时候,往往会遇到字节的网络顺序和主机顺序的问题.这是就可能用到htons(), ntohl(), n ...
- linux中find与rm实现查找并删除目录或文件
linux 下用find命令查找文件,rm命令删除文件. 删除指定目录下指定文件find 要查找的目录名 -name .svn |xargs rm -rf 删除指定名称的文件或文件夹: find -t ...
- Angular单元测试
https://angular.github.io/protractor/#/http://jasmine.github.io/2.4/introduction.html 测试程序有两种主要方法:端对 ...
- npm package.json中的dependencies和devDependencies的区别
转载:http://www.cnblogs.com/jes_shaw/p/4497836.html 一个node package有两种依赖,一种是dependencies一种是devDependenc ...