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

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

最近在学习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. 如何用Python批量发现互联网“开放”摄像头

    现在无论家用还是公司使用摄像头越来越多,但是安全性又如何呐?今天我来说说几款比较常用的摄像头,并且使用python如何批量检查弱口令. 第一个“海康威视”: 前段时间爆出海康威视的摄像头存在默认弱口令 ...

  2. weex 小结

    1. import  文件时,必须引入全称,不能省略 .vue import mEcharts from '../components/Echarts.vue' 2.weex 的 cli 中没有 配置 ...

  3. node 爬虫 --- 将爬取到的数据,保存到 mysql 数据库中

    步骤一:安装必要模块 (1)cheerio模块 ,一个类似jQuery的选择器模块,分析HTML利器. (2)request模块,让http请求变的更加简单 (3)mysql模块,node连接mysq ...

  4. Linux的SOCKET编程详解(转)

    Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系 ...

  5. CSS 的导入方式 (link or import ?)

    前言 最常看见的CSS的使用方式有三种 1. 在span, div 等标签上直接使用 style 属性定义CSS <span style="color:blue">Th ...

  6. Java 实现原型(Prototype)模式

    public class BaseSpoon implements Cloneable {//spoon 匙, 调羹 String name; public String getName() { re ...

  7. 实现多线程的方式Runnable

    package com.thread.runnable; /** * 实现多线程的方式有继承Thread类和实现Runnable接口两种方式 * 哪种方式更好呢?实现的方式由于继承的方式. * 原因: ...

  8. Struts2实现空表单信息的提示

    须要的jar包文件: index.jsp源代码: <%@ page language="java" contentType="text/html; charset= ...

  9. C++ Primer 学习笔记与思考_7 void和void*指针的使用方法

    (一)void的含义 void的字面意思是"无类型",void差点儿仅仅有"凝视"和限制程序的作用,由于从来没有人会定义一个void变量,让我们试着来定义: v ...

  10. BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 第8章节--配送SP2013Apps 应用程序生命周期

    BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第8章节--配送SP2013Apps 应用程序生命周期         你在商店拥有一个应用程序后.跟踪不论什么人们碰到的 ...