Hadoop(十一)Hadoop IO之序列化与比较功能实现详解
阅读目录(Content)
前言
上一篇给大家介绍了Hadoop是怎么样保证数据的完整性的,并且使用Java程序来验证了会产生.crc的校验文件。这一篇给大家分享的是Hadoop的序列化!
一、序列化和反序列化概述
1.1、序列化和反序列化的定义
1)序列化:将结构化对象转换为字节流的过程,以便在网络上传输或写入到磁盘进行永久存储的过程。
2)反序列化:将字节流转回一系列的相反过程结构化对象。
注意:其实流就是字节数组,我们把数据转变成一系列的字节数组(0101这样的数据)
1.2、序列化和反序列化的应用
1)进程间的通信
2)持久化存储
1.3、RPC序列化格式要求
在Hadoop中,系统中多个节点上进程间的通信是通过“远程过程调用(RPC)”实现的。RPC协议将消息序列化成 二进制流后发送到远程节点,远程节点
将二进制流反序列化为原始信息。通常情况下,RPC序列化格式如下:
1)紧凑(compact)
紧凑格式能充分利用网络带宽。
2)快速(Fast)
进程间通信形成了分布式系统的骨架,所以需要尽量减少序列化和反序列化的性能开销,这是基本..最基本的。
3)可扩展(Extensible)
为了满足新的需求,协议不断变化。所以控制客户端和服务器的过程中,需要直接引进相应的协议。
4)支持互操作(Interoperable)
对于某些系统来说,希望能支持以不同语言写的客户端与服务器交互,所以需要设计需要一种特定的格式来满足这一需求。
二、Hadoop中和虚序列化相关的接口和类
在Java中将一个类写为可以序列化的类是实现Serializable接口
在Hadoop中将一个类写为可以序列化的类是实现Writable接口,它是一个最顶级的接口。
1.1、Hadoop对基本数据类型的包装
Hadoop参照JDK里面的数据类型实现了自己的数据类型,Hadoop自己实现的原理会使数据更紧凑一些,效率会高一些。序列化之后的字节数组大小会比
JDK序列化出来的更小一些。
所有Java基本类型的可写包装器,除了char(可以是存储在IntWritable中)。所有的都有一个get()和set()方法来检索和存储包装值。
Java中的String对应着Hadoop中的Text,Text可以存储2G的字符串大小。
1.2、Writable接口
1)Writable接口概述
2)接口中的方法
Writable接口定义了两个方法:
一个将其状态写到DataOutput二进制流,另一个从DataInput二进制流读取状态。
3)API中Writable接口的例子:
public class MyWritable implements Writable { // Some data private int counter; private long timestamp; public void write(DataOutput out) throws IOException { out.writeInt(counter); out.writeLong(timestamp); } public void readFields(DataInput in) throws IOException { counter = in.readInt(); timestamp = in.readLong(); } public static MyWritable read(DataInput in) throws IOException { MyWritable w = new MyWritable(); w.readFields(in); return w; } }
思考:在Java中已经有序列化和反序列化相关的类和方法,为什么Hadoop还要去自己设计一套呢?
因为Hadoop认为Java设计的序列化和反序列化相关的类和方法性能不够好,效率太低了。所以就自己设计一套。
4)Writable的继承关系
1.3、实例解释Java和Hadoop数据类型序列化的差别
1)核心代码
2)测试结果
其实这里虽然是字节数组长度相同,但是在大数据中,其实是Hadoop占优势的。
1.4、在Hadoop中写一个序列化的类
1)核心代码
2)测试执行:
注意:" 第一部分":代表的是id,占四个字节。
“第二部分”:代表的是name,首先5是代表字符的长度,后面是字符的ASCII码。
注意如果将name的值改为中文,比如“二蛋子”如果是GBK编码就会占6个字节,如果是UTF-8编码就会占9个字节。
“第三部分”:代表的是gender,1表示ture,0表示false。
“第四部分”:在我们list中的size,虽然这里没有数据,但是int类型的仍然会占4个字节数。
四、Hadoop中和比较相关的接口和类
4.1、WritableComparable<T>接口
1)概述
继承了两个接口
2)相关方法
继承过来的三个方法
4.2、RawComparator<T>接口
1)概述
2)相关方法
除了Comparator中继承的两个方法,它自己也定义了一个方法有6个参数,这是在字节流的层面上去做比较。(第一个参数:指定字节数组,第二个参数:从哪里开始比较,第三个参数:比较多长)
在考虑到使用RawComparator比较不方便,有出现了一个实现类。
4.3、WritableComparator类
1)概述
2)构造方法
3)相关方法
截取了部分
介绍了上面的类和这些方法,我们Hadoop中有实现了一些既可以序列化也可以比较的类:
那我们如果自定义一个类型去实现比较的功能呢?在我们前面写了一个Student的类,它具有序列化的功能,那怎么样才能有比较的功能呢?
在Java中如果让一个类的对象具有可比较性
1)实现Comparable接口
2)编写独立的比较器,Comparator
而在Hadoop如果你要实现比较的功能有:
从上面的图中可以看出:
要是一个类具有比较功能又有序列化的功能可以去实现WritableComparable接口,如果你要一个类只要有比较功能
可以去写一个比较器用RawComparator或WritableComparator。
总的来说最好还是去实现WritableComparable接口,因为又有序列化的功能又有比较的功能。
五、Hadoop实现序列化和比较功能
功能分析:
5.1、核心代码
注意如果一个类即实现了WritableComparatable接口又写了比较器,优先使用比较器。