此文已由作者肖凡授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

最近在学习hadoop,发现hadoop的序列化过程和jdk的序列化有很大的区别,下面就来说说这两者的区别都有哪些。

1、先简单回顾下JAVA的序列化

JDK的序列化只要实现serializable接口OK了,但是有时需要加上序列化版本ID serialVersionUID ,这是为了:在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;而在另外一些场合,不希望类的不同版本对序列化兼容。

java的序列化算法的过程主要如下:

1) 将对象实例相关的类元数据输出。

2) 递归地输出类的超类描述直到不再有超类。

3) 类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。

4) 从上至下递归输出实例的数据

java的序列化很强大,对于复杂的情形,JAVA序列化机制也能应付自如,所以反序列化就so easy。 但是,Java的序列化机制的缺点也是很明显的,就是计算量开销大,且序列化的结果体积大太,有时能达到对象大小的数倍乃至十倍。它的引用机制也会导致大文件不能分割的问题,比如在一个很大的文件中反序列化某个对象时,需要访问文件中前面的某一个元数据,这将导致整个文件不能被切割,故而不能通过MapReduce来处理。同时,Java序列化会不断的创建新的对象,对于MapReduce应用来说,这将会带来大量的系统开销。这些缺点使得Java的序列化机制对Hadoop来说是不合适的。于是Hadoop设计了自己的序列化机制。

2、hadoop的序列化过程

对于处理大规模数据的Hadoop平台,其序列化机制需要具有如下特征:

1、紧凑:由于带宽是集群中信息传递的最宝贵的资源,所以我们必须想法设法缩小传递信息的大小。

2、快速:在进程间通信时会大量使用序列化机制,因此必须尽量减少序列化和反序列化的开销。

3、对象可重用:JDK的反序列化会不断地创建对象,这肯定会造成一定的系统开销,但是在hadoop的反序列化中,能重复的利用一个对象的readField方法来重新产生不同的对象。     为了支持以上这些特性,hadoo引入了Writeable的接口,作为所有可序列化对象必须实现的接口。Writable机制紧凑、快速,和serializable接口不同,Writable不是一个说明性的接口,它包含两个方法:

public interface Writable {  /** 
   * 输出(序列化)对象到流中
   * 
   * @param out DataOuput 流,序列化的结果保存在流中
   * @throws IOException
   */
  void write(DataOutput out) throws IOException;  /** 
   * 从流中读取(反序列化)对象
   * 为了效率,请尽可能复用现有的对象
   * @param in DataInput流,从该流中读取数据
   * @throws IOException
   */
  void readFields(DataInput in) throws IOException;
}

Writable.write()方法用于将对象状态写入二进制的DataOutput中,反序列化的过程由readFields()从DataInput流中读取状态完成。下面是一个例子:

public class MyWritable implements Writable {	private Text id;	private Text name;	public MyWritable(Text id, Text name) {		super();		this.id = id;		this.name = name;
} public synchronized Text getId() { return id;
} public synchronized void setId(Text id) { this.id = id;
} public synchronized Text getName() { return name;
} public synchronized void setName(Text name) { this.name = name;
} @Override
public void write(DataOutput out) throws IOException {
id.write(out);
name.write(out);
} @Override
public void readFields(DataInput in) throws IOException {
id.readFields(in);
name.readFields(in);
}
}

从上面的例子可以看出,write()和readFields()这两个方法的实现都很简单:MyWritable有两个成员变量,write()方法简单地把这两个成员变量写入流中,而readFields()则从流中依次读入这些数据。目前Java基本类型对应的Writable封装如下表所示:

Java基本类型

Writable

序列化后的长度

boolean

BooleanWritable

1

byte

ByteWritable

1

int

IntWritable

VIntWritable

4

1~5

float

FloatWritable

4

long

LongWritable

VLongWritable

8

1~9

double

DoubleWritable

8

从上表可以看出,对整形(int和long)进行编码的时候,有固定长度格式(IntWritable和LongWritable)和可变长度格式(VIntWritable和VLongWritable)两种选择。固定长度格式的整型,序列化后的数据时定长的,而可变长度格式则使用一种比较灵活的编码方式,对于数值比较小的整型,它们往往比较节省空间,这对于hadoop尤为重要。

3.Hadoop序列化框架

我们知道,大部分的MapReduce程序都使用Writable键-值对作为输入和输出,但这并不是Hadoop的API指定的,其它序列化机制也能够和Hadoop配合使用,目前除了前面提到的JAVA序列化机制和Hadoop使用的Writable机制,还流行其它的序列化框架,如Hadoop Avro、Apache Thrift和Google Protocol Buffer,有兴趣的同学可以去了解下。

Hadoop提供了一个简单的序列化框架API,用于集成各种序列化实现,该框架由Serialization接口实现。通过Serialization可以获得Serializer和Deserializer,分别用来将一个对象转换为一个字节流和将一个字节流转化为一个对象,相关代码如下:

public interface Serialization {  /**
   * 客户端用于判断序列化实现是否支持该类对象
   */
  boolean accept(Class c);  /**
   * 获得用于序列化对象的Serializer实现
   */
  Serializer getSerializer(Class c);  /**
   * 获得用于反序列化对象的Deserializer实现
   */
  Deserializer getDeserializer(Class c);
}

如果需要使用Serializer来执行序列化,一般通过open()方法打开Serializer,open()方法传入一个流对象,然后就可以使用serialize()方法序列化对象到流中,最后序列化结束后,通过close()方法关闭Serializer,相关代码如下:

public interface Serializer {  /**
   * 为输出对象做准备
   */
  void open(OutputStream out) throws IOException; 
  /**
   * 将对象序列化到底层的流中
   */
  void serialize(T t) throws IOException;  /**
   * 序列化结束,清理
   */  
  void close() throws IOException;
}

Hadoop目前支持两个Serialization实现,分别是支持Writable机制的WritableSerialization和支持Java序列化的JavaSerialization。通过JavaSerialization可以再MapReduce程序中使用标准的Java类型,但是这种序列化不如Hadoop的序列化机制有效,非特殊情况不要轻易尝试。

网易云免费体验馆,0成本体验20+款云产品!

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 Spring Cloud使用总结
【推荐】 Java web 服务启动时Xss溢出异常处理笔记
【推荐】 大数据技术在金融行业的应用前景

hadoop中的序列化的更多相关文章

  1. 1 weekend110的复习 + hadoop中的序列化机制 + 流量求和mr程序开发

    以上是,weekend110的yarn的job提交流程源码分析的复习总结 下面呢,来讲weekend110的hadoop中的序列化机制 1363157985066      13726230503  ...

  2. hadoop中的序列化与Writable接口

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable-interface.html,转载请注明源地址. 简介 序列化和反序列化就是结构化对象 ...

  3. hadoop中的序列化与Writable类

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable-class.html,转载请注明源地址. hadoop中自带的org.apache.h ...

  4. 一脸懵逼学习Hadoop中的序列化机制——流量求和统计MapReduce的程序开发案例——流量求和统计排序

    一:序列化概念 序列化(Serialization)是指把结构化对象转化为字节流.反序列化(Deserialization)是序列化的逆过程.即把字节流转回结构化对象.Java序列化(java.io. ...

  5. Hadoop中序列化与Writable接口

    学习笔记,整理自<Hadoop权威指南 第3版> 一.序列化 序列化:序列化是将 内存 中的结构化数据 转化为 能在网络上传输 或 磁盘中进行永久保存的二进制流的过程:反序列化:序列化的逆 ...

  6. Hadoop中客户端和服务器端的方法调用过程

    1.Java动态代理实例 Java 动态代理一个简单的demo:(用以对比Hadoop中的动态代理) Hello接口: public interface Hello { void sayHello(S ...

  7. Hadoop中WritableComparable 和 comparator

    1.WritableComparable 查看HadoopAPI,如图所示: WritableComparable继承自Writable和java.lang.Comparable接口,是一个Writa ...

  8. hadoop文件的序列化

    目录 1.为什么要序列化? 2.什么是序列化? 3.为什么不用Java的序列化? 4.为什么序列化对Hadoop很重要? 5.Hadoop中定义哪些序列化相关的接口呢? 6.Hadoop 自定义Wri ...

  9. Hadoop 中 IPC 的源码分析

    最近开始看 Hadoop 的一些源码,展开hadoop的源码包,各个组件分得比较清楚,于是开始看一下 IPC 的一些源码. IPC模块,也就是进程间通信模块,如果是在不同的机器上,那就可以理解为 RP ...

随机推荐

  1. 取汉子拼音首字母的C#方法

    /// <summary> /// 获得一个字符串的汉语拼音码 /// </summary> /// <param name="strText"> ...

  2. 有关不同浏览器不同版本号的css以及js计算高度的问题

    1.input在全部浏览器以及全部的版本号中,都是定义了高度.然后再定义padding或者border值.这时候都会撑开.高度是本身的高度在padding值和border值 2.select在gool ...

  3. mysql中游标在存储过程中的具体使用方法

    昨天写的一个东东,分享下给大家. drop PROCEDURE  if exists sp_cleanUserData; CREATE  PROCEDURE `sp_cleanUserData`()  ...

  4. 软件系统架构 https://www.lanhusoft.com/Article/349.html

    跟蓝狐学习Nop--NopCommerce源码架构详解专题目录 Posted By : 蓝狐 Updated On : 2018-04-16 14:46 我们承接以下nop相关的业务,欢迎联系我们. ...

  5. wamp配置虚拟域名

    1.打开apache下httpd.conf 我的目录是在F:\wamp\bin\apache\apache2.2.22\conf\httpd.conf 2.去掉这两行前面的#注释 LoadModule ...

  6. ansible 基本命令学习与踩坑

    1. 命令行参数 -v,–verbose 详细模式,如果命令执行成功,输出详细的结果(-vv –vvv -vvvv) -i PATH,–inventory=PATH 指定host文件的路径,默认是在/ ...

  7. Qt、C++ 简易计算器

    Qt.C++实现简易计算器: 以下内容是我实现这个简易计算器整个过程,其中包括我对如何实现这个功能的思考.中途遇到的问题.走过的弯路 整个实现从易到难,计算器功能从简单到复杂,最开始设计的整个实现步骤 ...

  8. Django-权限信息自定义标签

    自定义权限标签: import re from django.template import Library from django.conf import settings register = L ...

  9. Android Webview的测试

    1.查看当前的所有窗口: Set contexts= driver.getContextHandles(); System.out.println(contexts); 打印出当前所有的窗口 Set& ...

  10. 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有測试代码(何志雄)

    转载请标明出处. 在分布式系统中,常常会出现须要竞争同一资源的情况,本代码基于redis3.0.1+jedis2.7.1实现了分布式锁. redis集群的搭建,请见我的另外一篇文章:<>& ...