1.1. 序列化
org.apache.hadoop.io包
序列化:将一个对象编码为一个字节流
反序列化:相反过程
用途:
1、 作为一种持久化格式:可存储在硬盘上,供以后反序列化使用
2、 作为一种通信数据格式:可在JVM之间,通过网路相互传递
3、 复制的机制:深度复制
1.1.1. java内建序列化机制:
只有实现Serializabl接口(声明)即可。
对象输出流ObjectOutputStream 的writeObject(obj)方法
序列化输出的结果中包含了大量与类有关的信息。
对象输入流ObjectInputStream的readObject()方法,读取对象时必须小心跟踪存储对象的数量、顺序和类型
对于父类的处理,如果父类没有实现串行化接口,则其必须有默认的构造函数(即没有参数的构造函数)。否则编译的时候就会报错。在反串行化的时候,默认构造函数会被调用(即会调用构造方法创建新的对象)。但是若把父类标记为可以串行化,则在反串行化的时候,其默认构造函数不会被调用。这是为什么呢?这是因为Java 对串行化的对象进行反串行化的时候,直接从流里获取其对象数据来生成一个对象实例,而不是通过其构造函数来完成(即无新的对象进行构造)。
package com.test; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class SerialDemo { public static void main(String[] args) throws Exception { //待写入的对象 String obj1 = "Hello world!"; FileOutputStream fos = new FileOutputStream("test.out"); ObjectOutputStream out = new ObjectOutputStream(fos); out.writeObject(obj1); out.writeInt(1024); out.close(); fos.close(); //顺序读取对象 ObjectInputStream in = new ObjectInputStream(new FileInputStream("test.out")); String temp = (String) in.readObject(); int temp2 = in.readInt(); System.out.println(temp+temp2); in.close(); } }
java序列化输出保存了大量的附加信息,导致序列化结果膨胀,对于需要保存和处理大规模数据的hadoop来说,需要一个新的序列化机制。
java反序列化会不断的创建新的对象(hadoop的不会,而是实现了对对象的复用)
1.1.1. hadoop序列化
实现了Writable接口,write(out) 和readFileds(in)方法
实验:同时输出三个long类型的长度
package test; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectOutputStream; import org.apache.hadoop.hdfs.protocol.Block; public class SerialDemo { public static void main(String[] args) throws Exception { test1(); test2(); } private static void test2() throws IOException { //第一个参数为block的Id,第二个为分配的长度,第三个戳,共三个标志 //此Block为自定义块,而不是使用hadoop自带的。可以看后面 Block block1 = new Block(1L,24L,1L); ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream dout1 = new DataOutputStream(bout); //序列化对象到IO流中 block1.write(dout1); System.out.println("hadoop序列化长度(三个long):"+bout.size()); } private static void test1() throws FileNotFoundException, IOException, ClassNotFoundException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.writeLong(1L); out.writeLong(1L); out.writeLong(1L); out.close(); System.out.println("java序列化长度(三个long):"+bout.size()); } }
结果:
java序列化长度(三个long):30
hadoop序列化长度(三个long):24
1.1.1. hadoop序列化特征
1、 紧凑,带宽是hadoop集群中最稀缺的资源,一个紧凑的序列化机制可以充分利用数据中心的带宽
2、 快速:进程间通信,会大量使用序列化机制,因此,必须尽量减少序列化和反序列化的开销
3、 可扩展:升级
4、 互操作:不同语言之间的通信
引入了org.apache.hadoop.io.Writable接口,作为所有可序列化对象必须实现的接口
示例:
class Block implements Writable{ private long blockId; private long numBytes; private long stamp; public Block(long blockId, long numBytes, long stamp) { super(); this.blockId = blockId; this.numBytes = numBytes; this.stamp = stamp; } @Override public void readFields(DataInput in) throws IOException { // TODO Auto-generated method stub blockId = in.readLong(); numBytes = in.readLong(); stamp = in.readLong(); } @Override public void write(DataOutput out) throws IOException { // TODO Auto-generated method stub out.writeLong(blockId); out.writeLong(numBytes); out.writeLong(stamp); } }
hadoop序列化的重要接口:
WritableComparable 类型比较接口,用于key的自定义实现如IntWritable,LongWritable等java基本类型和Text等
RawComparable(读取时) 实现高效比较能力,允许直接比较流中对象,省去创建对象的所有开销,选择时可以按需所取。
public int compare (byte[] b1,int s1,int e1,byte[] b2,int s2,int e2);
WritableComparator:实现了接口RawComparable,同时提供了一个获取一个Writable类的比较器
com = WritableComparator.get(IntWritable.class);//获取IntWritable的比较器
典型的Writable类:(short和char没有实现,可以使用IntWritable)
对于可变长度,因内部实现存在许多逻辑判断,不建议使用。
对于ObjectWritable作为一种通用的标志,相当浪费资源,如果类型的数量不多,可以通过一个静态数组来提高效率,并使用数组的索引作为类型的序列化引用。不建议使用。实际上,对于自定义的类型已满足需求。
另外还有一个GenericWritable类,用于对ObjectWritable进行替换,也不建议使用,内部逻辑判断很多。
1.1.1. hadoop的序列化框架
除了Writable其它的序列化框架也能和Hadoop配合。(可在实际需要时采用)
1、Avro:动态语言友好,可以使用Python等实现Mapreduce
2、Thrift:跨语言的服务开发框架
3、Google Protocol Buffer 提供了轻便高效的结构化数据存储格式,支持C++,java,python三者语言的API。
hadoop通过一个简单的序列化API,集成各种序列化的实现。有org.apache.hadoop.io.serializer包里的Serialization实现
private static void test3(){ //对一个long类型进行序列化 ByteArrayOutputStream bout = new ByteArrayOutputStream(); SerializationUtils.serialize(1L, bout); System.out.println("hadoop Serialization序列化长度(1个long):"+bout.size()); long temp = (Long) SerializationUtils.deserialize(SerializationUtils.serialize(1L)); System.out.println(temp); }
结果:
hadoop Serialization序列化长度(1个long):82
1
长度竟然为82,所以不建议使用hadoop的Serialization
来源:https://www.cnblogs.com/jsunday/p/3817430.html