Java 和 Hadoop 序列化机制浅讲

1.序列化

序列化
(Serialization)将对象的状态信息转换为可以存储或传输的形式的过程(字节流)。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

通常来说有三个用途:

  • 持久化:对象可以被存储到磁盘上
  • 通信:对象可以通过网络进行传输
  • 拷贝、克隆:可以通过将某一对象序列化到内存的缓冲区,然后通过反序列化生成该对象的一个深拷贝(破解单例模式的一种方法)

2.Java序列化机制

在Java中要实现序列化,只需要实现Serializable即可(说是实现,其实不需要实现任何成员方法)。

public interface Serializable {
}

如果想对某个对象进行序列化的操作,只需要在OutputStream对象上创建一个输入流 ObjectOutputStream 对象,然后调用 writeObject()。在序列化过程中,对象的类、类签名、雷瑟所有非暂态和非静态成员变量的值,以及它所有的父类都会被写入。

Date d = new Date();
OutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(d);

如果想对某个基本类型进行序列化,ObjectOutputStream 还提供了多种 writeBoolean、writeByte等方法

反序列过程类似,只需要调用 ObjectInputStream 的 readObject() ,并向下转型,就可以得到正确结果。

优点:实现简便,对于循环引用和重复引用的情况也能处理,允许一定程度上的类成员改变。支持加密,验证。

缺点:序列化后的对象占用空间过大,数据膨胀。反序列会不断创建新的对象。同一个类的对象的序列化结果只输出一份元数据(描述类关系),导致了文件不能分割。

3.Hadoop序列化机制

对于需要保存和处理大规模数据的Hadoop来说,其序列化机制要达到以下目的:

  • 排列紧凑:尽量减少带宽,加快数据交换速度
  • 处理快速:进程间通信需要大量的数据交互,使用大量的序列化机制,必须减少序列化和反序列的开支
  • 跨语言:可以支持不同语言间的数据交互啊,如C++
  • 可扩展:当系统协议升级,类定义发生变化,序列化机制需要支持这些升级和变化

为了支持以上特性,引用了Writable接口。和说明性Serializable接口不一样,它要求实现两个方法。

public interface Writable {
  void write(DataOutput out) throws IOException;
  void readFields(DataInput in) throws IOException;
}

比如,我们需要实现一个表示某一时间段的类,就可以这样写

public class StartEndDate implements Writable{
	private Date startDate;
	private Date endDate;

	@Override
	public void write(DataOutput out) throws IOException {
		out.writeLong(startDate.getTime());
		out.writeLong(endDate.getTime());
	}

	@Override
	public void readFields(DataInput in) throws IOException {
		startDate = new Date(in.readLong());
		endDate = new Date(in.readLong());
	}

	public Date getStartDate() {
		return startDate;
	}
	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}

}

Hadoop 还提供了另外几个重要的接口:

WritableComparable:它不仅提供序列化功能,而且还提供比较的功能。这种比较式基于反序列后的对象成员的值,速度较慢。

RawComparator:由于MapReduce十分依赖基于键的比较排序(自定义键还需要重写hashCode和equals方法),因此提供了一个优化接口
RawComparator。该接口允许直接比较数据流中的记录,无需把数据流反序列化为对象,这样避免了新建对象的额外开销。RawComparator定义如下,compare方法可以从每个字节数组b1和b2中读取给定起始位置(s1和s2)以及长度l1和l2的一个整数直接进行比较。

public interface RawComparator<T> extends Comparator<T> {

  public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2);

}

WritableComparator: 是 RawComparator 的一个通用实现,提供两个功能:提供了一个 RawComparator的comparea()的默认实现,该默认实现只是反序列化了键然后再比较,没有什么性能优势。其次、充当了
RawComaprator 实例的一个工厂方法。

当我们要实现自定key排序时(自定义分组),需要指定自己的排序规则。

如需要以StartEndDate为键且以开始时间分组,则需要自定义分组器:

class MyGrouper implements RawComparator<StartEndDate> {
    @Override
    public int compare(StartEndDate o1, StartEndDate o2) {
        return (int)(o1.getStartDate().getTime()- o2.getEndDate().getTime());
    }
    @Override
    public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
        int compareBytes = WritableComparator.compareBytes(b1, s1, 8, b2, s2, 8);
        return compareBytes;
    }

}

然后在job中设置

job.setGroupingComparatorClass(MyGrouper.class);

最好将equals和hashcode也进行重写:

	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof StartEndDate))
			return false;
		StartEndDate s = (StartEndDate)obj;
		return startDate.getTime()== s.startDate.getTime()&&endDate.getTime() == s.endDate.getTime();
	}
	@Override
	public int hashCode() {
		int result = 17;  //任意素数
		 result = 31*result +startDate.hashCode();
		 result = 31*result +endDate.hashCode();
		 return result;
	};

ps: equal 和 hashcode 方法中应该还要对成员变量判空,以后还需要修改。

参考资料:

《Hadoop权威指南》

《Hadoop技术内幕》

正确重写hashCode的方法 -http://blog.sina.com.cn/s/blog_700aa8830101jtlf.html

MapReduce自定义分组 -http://www.luoliang.me/index.php/archives/ProgrammingLanguage/56.html

时间: 2024-10-09 03:05:02

Java 和 Hadoop 序列化机制浅讲的相关文章

Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

酒,是个好东西,前提要适量.今天参加了公司的年会,主题就是吃.喝.吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个喷子!在大家推杯换盏之际,难免一些画面浮现脑海,有郁闷抓狂的,有出成果喜极而涕的,有不知前途在哪儿的迷茫与不安……总的来说,近一年来,不白活,不虚度,感触良多,不是一言两语能说得清道的明的,有时间可以做个总结,下面还是言归正传谈技术吧. 上篇在了解了Hadoop的目录和源码结构后,说好的要啃源码的,那就得啃.也感谢一直以来关注我.支持我的网友

Hadoop序列化机制及实例

序列化 1.什么是序列化? 将结构化对象转换成字节流以便于进行网络传输或写入持久存储的过程. 2.什么是反序列化? 将字节流转换为一系列结构化对象的过程. 序列化用途: 1.作为一种持久化格式. 2.作为一种通信的数据格式. 3.作为一种数据拷贝.克隆机制. Java序列化和反序列化 1.创建一个对象实现了Serializable 2.序列化:ObjectOutputStream.writeObject(序列化对象) 反序列化:ObjectInputStream.readObject()返回序列

大数据框架hadoop的序列化机制

Java内建序列化机制 在Windows系统上序列化的Java对象,可以在UNIX系统上被重建出来,不需要担心不同机器上的数据表示方法,也不需要担心字节排列次序. 在Java中,使一个类的实例可被序列化非常简单,只需要在类声明中加入implements Serializable即可.Serializable接口是一个标志,不具有任何成员函数,其定义如下: public interface Serializable { } Block类通过声明它实现了Serializable 接口,立即可以获得J

Hadoop序列化与压缩

传统的的计算机系统通过I/O操作与外界交流,,Hadoop的I/O由传统的I/O系统发展而来,但是又有些不同,Hadoop需要处理P.T级别的数据,所以在org.apache.hadoop.io包中包含了一些面向海量数据处理的基本输入输出工具,本文会对其中的序列化和压缩进行研究. 1 序列化 对象的序列化用于将对象编码成一个字节流,以及从字节流中重新构建对象.将一个对象编码成一个字节流称为序列化对象(Serializing),相反的处理过程称为反序列化. 序列化有三种主要的用途: A.作为一种持

Java对象深复制、浅复制

我们在编码过程经常会碰到将一个对象传递给另一个对象,java中对于基本型变量采用的是值传递,而对于对象比如bean传递时采用的引用传递也就是地址传递,而很多时候对于对象传递我们也希望能够象值传递一样,使得传递之前和之后有不同的内存地址,在这种情况下我们一般采用以下两种情况. 浅复制与深复制概念 浅复制(浅克隆) :被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. 深复制(深克隆) :被复制对象

Hadoop序列化与Java序列化

序列化就是把内存中的对象的状态信息转换成字节序列,以便于存储(持久化)和网络传输 反序列化就是就将收到的字节序列或者是硬盘的持久化数据,转换成内存中的对象. 1.JDK的序列化 只要实现了serializable接口就能实现序列化与反序列化,一定要加上序列化版本ID serialVersionUID,这个是用来识别序列化的之前的类到底是哪一个.比如希望类的不同版本对序列化兼容,需要确保类的不同版本具有相同的serialVersionUID: Java序列化算法需要考虑: 将对象实例相关的类元数据

java反射机制浅谈

一.Java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动,说不定会请各位吃饭哦! 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 2.反射

Java序列化与反序列化学习(三):序列化机制与原理

Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的 过程.Java序列化API提供一种处理对象序列化的标准机制.在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用 一个实例来示范序列化以后的字节是如何描述一个对象的信息的. 序列化的必要性 Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端.这就需要有一种

Java序列化机制剖析

Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.Java序列化API提供一种处理对象序列化的标准机制.在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的. 序列化的必要性 Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端.这就需要有一种可以