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;  
}

copy

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深入研究:(十三)——序列化框架的更多相关文章

  1. 5.3.4 Hadoop序列化框架

    序列化框架 除了writable实现序列化之外,只要实现让类型和二进制流相互转换,都可以作为hadoop的序列化类型,为此Hadoop提供了一个序列化框架接口,他们在org.apache.hadoop ...

  2. Mapreduce之序列化框架(转自http://blog.csdn.net/lastsweetop/article/details/9376495)

    框架简介 MapReduce仅仅可以支持Writable做key,value吗?答案是否定的.事实上,一切类型都是支持的,只需满足一个小小的条件:每个类型是以二进制流的形式传输.为此Hadoop提供了 ...

  3. Hadoop的简单序列化框架

    Hadoop提供了一个加单的序列化框架API,用于集成各种序列化实现.该框架由Serialization实现. 其中Serialization是一个接口,使用抽象工厂的设计模式,提供了一系列和序列化相 ...

  4. 为什么hadoop中用到的序列化不是java的serilaziable接口去序列化而是使用Writable序列化框架

    继上一个模块之后,此次分析的内容是来到了Hadoop IO相关的模块了,IO系统的模块可谓是一个比较大的模块,在Hadoop Common中的io,主要包括2个大的子模块构成,1个是以Writable ...

  5. [java]序列化框架性能对比(kryo、hessian、java、protostuff)

    序列化框架性能对比(kryo.hessian.java.protostuff) 简介:   优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Pro ...

  6. 二进制序列化框架easypack发布啦!

    简介 easypack是基于boost.serialization的二进制序列化框架,使用极其方便. Examples 基本类型 int age = 20; std::string name = &q ...

  7. hadoop深入研究:(五)——Archives

    转载请注明来源地址:http://blog.csdn.net/lastsweetop/article/details/9123155 简介 我们在hadoop深入研究:(一)——hdfs介绍里已讲过, ...

  8. hadoop深入研究:(七)——压缩

    转载请标明出处:hadoop深入研究:(七)——压缩 文件压缩主要有两个好处,一是减少了存储文件所占空间,另一个就是为数据传输提速.在hadoop大数据的背景下,这两点尤为重要,那么我现在就先来了解下 ...

  9. Java序列化框架性能比較

    博客: http://colobu.com jvm-serializers提供了一个非常好的比較各种Java序列化的的測试套件. 它罗列了各种序列化框架. 能够自己主动生成測试报告. 我在AWS c3 ...

随机推荐

  1. 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 ...

  2. 六.__FILE__ , __LINE__ 与调试日志

    很多人可能不知道,C\C++编译器提供了一套针对代码文件的宏定义,它们能够帮助开发者更好的定位代码的BUG. __FILE__ 该宏定义是一个字符串,存储着当前代码文件的完整路径 __LINE__ 该 ...

  3. awk处理nmap扫描结果

    接到个任务,要对大量的主机ip进行扫描: 扫描加过滤脚本贴到底下 #!/bin/bash ### use nmap scan aliyun echo "********Start scan* ...

  4. 2018-2019-1 20189215《Linux内核原理与分析》第三周作业

    <庖丁解牛>第二章书本知识总结 函数调用框架 call指令有两个作用: (1) 将CS:EIP中下一条指令的地址A保存在栈顶: (2)设置CS:EIP指向被调用程序的第一行. ret指令在 ...

  5. HDU 6342 Expression in Memories(模拟)多校题解

    题意:给你一个规则,问你写的对不对. 思路:规则大概概括为:不能出现前导零,符号两边必须是合法数字.我们先把所有问号改好,再去判断现在是否合法,这样判断比一边改一边判断容易想. 下面的讲解问号只改为+ ...

  6. js的原型继承

    <script> //动物(Animal),有头这个属性,eat方法 //名字这个属性 //猫有名字属性,继承Animal,抓老鼠方法 function Animal(name){ thi ...

  7. C++网络通信字节序问题

    htonl(), ntohl(), htons(), ntohs() 函数 在C/C++写网络程序的时候,往往会遇到字节的网络顺序和主机顺序的问题.这是就可能用到htons(), ntohl(), n ...

  8. linux中find与rm实现查找并删除目录或文件

    linux 下用find命令查找文件,rm命令删除文件. 删除指定目录下指定文件find 要查找的目录名 -name .svn |xargs rm -rf 删除指定名称的文件或文件夹: find -t ...

  9. Angular单元测试

    https://angular.github.io/protractor/#/http://jasmine.github.io/2.4/introduction.html 测试程序有两种主要方法:端对 ...

  10. npm package.json中的dependencies和devDependencies的区别

    转载:http://www.cnblogs.com/jes_shaw/p/4497836.html 一个node package有两种依赖,一种是dependencies一种是devDependenc ...