5.1 Hadoop数据序列化
来源:互联网 发布:在a标签传随机参数js 编辑:程序博客网 时间:2024/06/06 12:41
5.1 Hadoop数据序列化
尽管我们看到的数据是结构化的形式,但数据的原始形式是序列化的比特或比特流。数据以这种原始形式通过网络传输,然后保存在RAM或其他持久性存储媒体中。序列化过程就是把结构化的数据转换为原始形式。反序列化过程则相反,是把数据从原始比特流形式重建为结构形式。
Hadoop中不同的组件使用远程调用(Remote Procedure Call,RPC)进行交互。在发送调用函数名和参数给被调方之前,调用方进程会把它们序列化为字节流。被调方反序列化这个字节流,解释函数类型,根据所提供的参数执行函数,最后序列化执行结果,并放回调用方。当然,整个工作流需要快速的序列化和反序列化。网络带宽十分珍贵,所以需要序列化函数名和函数参数,从而尽可能减小负载。不同的组件会以不同的方式变化,所以整个序列化-反序列化过程需要向后兼容和可扩展。运行在不同机器上的组件进程会有不同的配置,并且所利用的平台组件也不同,因此序列化-反序列化库需要具备交互操作性能。序列化和反序列化的这些特性不限于网络数据,还适用于存储,包括易失存储和持久存储。
5.1.1 Writable与WritableComparable
Hadoop序列化和反序列化都使用Writable接口。这个接口有两个方法,void write(DataOutput out)和void readFields(DataInput in)。write方法序列化对象为字节流。readFields方法则是反序列化方法,即读取输入的字节流并将其转换为对象。
继承Writable接口的是WritableComparable接口。可以说这个接口是Writable接口和Comparable接口的组合。接口的实现类不但可以方便地进行序列化和反序列化,而且还能对值进行比较。用Hadoop数据类型实现这个接口,可以非常方便的排序和分组数据对象。
Hadoop提供了许多唾手可得的WritableComparable包装类。每个WritableComparable包装类对应包装一个Java原生类型。例如,IntWritable包装类包装了int数据点(data point),BooleanWritable包装类包装了boolean类型。
Hadoop有VIntWritable和VLongWritable类,它们长度可变,但相对于固定长度的IntWritable和LongWritable类型。处于-112到127之间的值会使用可变长度数值类型编码为单个字节。然而,更大的数值用另一种方式编码,即首字节代表标记以及紧跟其后的字节数。当数值分布的方差很高时,平均而言,可变长度的Writable能节省存储空间。数值越小,所需存储空间就越小。
演示程序MasteringHadoopSerialization.java
package MasteringHadoop;import org.apache.hadoop.io.*;import org.apache.hadoop.util.StringUtils;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;public class MasteringHadoopSerialization{ public static String serializeToByteString(Writable writable) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream); //使用你write方法把Writable对象序列化为字节流 writable.write(dataOutputStream); dataOutputStream.close(); byte[] byteArray = outputStream.toByteArray(); //StringUtils工具类的方法把字节数组转换为十六进制字符串 return StringUtils.byteToHexString(byteArray); } public static String javaSerializeToByteString(Object o) throws IOException{ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(o); objectOutputStream.close(); byte[] byteArray = outputStream.toByteArray(); return StringUtils.byteToHexString(byteArray); } public static void main(String[] args) throws IOException{ IntWritable intWritable = new IntWritable(); VIntWritable vIntWritable = new VIntWritable(); LongWritable longWritable = new LongWritable(); VLongWritable vLongWritable = new VLongWritable(); int smallInt = 100; int mediumInt = 1048576; long bigInt = 4589938592L; System.out.println("smallInt serialized value using IntWritable"); intWritable.set(smallInt); System.out.println(serializeToByteString(intWritable)); System.out.println("smallInt serialized value using VIntWritable"); vIntWritable.set(smallInt); System.out.println(serializeToByteString(vIntWritable)); System.out.println("mediumInt serialized value using IntWritable"); intWritable.set(mediumInt); System.out.println(serializeToByteString(intWritable)); System.out.println("mediumInt serialized value using VIntWritable"); vIntWritable.set(mediumInt); System.out.println(serializeToByteString(vIntWritable)); System.out.println("bigInt serialized value using LongWritable"); longWritable.set(bigInt); System.out.println(serializeToByteString(longWritable)); System.out.println("mediumInt serialized value using VIntWritable"); vLongWritable.set(bigInt); System.out.println(serializeToByteString(vLongWritable)); System.out.println("smallInt serialized value using Java serializer"); System.out.println(javaSerializeToByteString(new Integer(smallInt))); System.out.println("mediumInt serialized value using Java serializer"); System.out.println(javaSerializeToByteString(new Integer(mediumInt))); System.out.println("bigInt serialized value using Java serializer"); System.out.println(javaSerializeToByteString(new Long(bigInt))); }}
运行部分结果:
smallInt serialized value using IntWritable00000064smallInt serialized value using VIntWritable64mediumInt serialized value using IntWritable00100000mediumInt serialized value using VIntWritable8d100000bigInt serialized value using LongWritable000000011194e7a0mediumInt serialized value using VIntWritable8b011194e7a0
不管存放的数值大小,IntWritable类始终使用4个字节的固定长度来表示一个整形。而VIntWritable类更聪明,字节数取决于数值的大小。对于数值100,VIntWritable只使用1个字节。LongWritable和VLongWritable在序列化值的时候有类似区别。Text是Writable版的String类型。它代表UTF-8字符集合。相比Java的String类,Hadoop中的Text类时可变的。
5.1.2 Hadoop与Java序列化的区别
在此有一个疑问,为什么Hadoop用Writable接口来序列化而不使用Java序列化?让我们使用上面演示程序中的javaSerializeToByteString()方法。在该方法中Java提供ObjectOutputStream类来把对象序列化为字节流。ObjectOutputStream类型有writeObject方法。
程序部分输出结果:
smallInt serialized value using Java serializeraced0005737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000064mediumInt serialized value using Java serializeraced0005737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000100000bigInt serialized value using Java serializeraced00057372000e6a6176612e6c616e672e4c6f6e673b8be490cc8f23df0200014a000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b0200007870000000011194e7a0
显然,这个序列化后的值大于Writable序列化后的值。Hadoop是在磁盘或网络上进行序列化和反序列化的,所以简洁有效极为重要。而Java序列化因为要标识对象,所以消耗了更多的字节。
Java不假设序列化的值类型,这是Java序列化低效的根本原因。这就需要在每个序列化结果中标记类相关的元数据。然而,Writable类则从字节流中读取字段,并假设字节流的类型。更简洁的序列化结果极大地提高了性能。但是这样增加了Hadoop新手的学习难度。另一个缺点是Writable类只适用于Java编程语言。
编写自定义的Writable类很乏味,因为开发人员不得不考虑网络传输中的类格式。Hadoop中临时引入了Record IO,这个功能使用了记录定义语言(record definition language),同时提供了编译器能把记录定义转换为Writable类。最终,这个功能被废弃,Avro取而代之。
在Hadoop 0.17之前,任何MapReduce程序中,Map和Reduce任务的键和值都基于Writable类。然而,在之后的版本,Hadoop中的MapReduce作业可以于任何序列化框架集成。这使得有很多序列化框架可供选择。每个序列化框架都带来了性能提升,有的是以简洁见长,有的是以序列化和反序列化的速度见长,或两者兼备。
- 5.1 Hadoop数据序列化
- 【Hadoop】数据序列化系统Avro
- 大数据之hadoop[序列化与压缩]
- Hadoop--序列化
- hadoop序列化
- Hadoop的序列化
- Hadoop序列化
- Hadoop序列化
- Hadoop序列化案例
- hadoop序列化
- [Hadoop]序列化机制
- hadoop序列化框架
- hadoop自定义序列化
- Hadoop 序列化
- hadoop中的序列化
- HADOOP序列化机制
- Hadoop 序列化
- Hadoop序列化
- 使用 spring.profiles.active 及 @profile 注解 动态化配置内部及外部配置
- hbase存储大数据量相关配置调优
- PAT甲级 1055. The World's Richest (25)
- Greendao 简单实现增删改查使用过GreenDao的同学都知道,3.0之前需要通过新建GreenDaoGenerator工程生成Java数据对象(实体)和DAO对象,非常的繁琐而且也加大了使用成
- java桃心形状
- 5.1 Hadoop数据序列化
- VMWare VMNet 8 的配置使用
- Android 源码系列之<十七>自定义Gradle Plugin,优雅的解决第三方Jar包中的bug<上>
- 多元线性回归
- IntelliJ IDEA For Mac 快捷键
- Hololens开发时注意的地方
- 【Mybatis】出现The error may involve defaultParameterMap错误
- cdev、misc以及device三者之间的联系和区别
- Netty学习笔记(一) 配置Netty环境