此文是一篇读书笔记,由于刚刚接触,很多知识点没有深入。很多地方存在不合理之处,望指出,谢谢。深入知识点会后续补上。
老鸟就不用看了;
Hadoop工程下与I/O相关的包如下:
org.apache.hadoop.io
org.apache.hadoop.io.compress
org.apache.hadoop.io.file.tfile
org.apache.hadoop.io.serializer
org.apache.hadoop.io.serializer.avro
除了org.apache.hadoop.io.serializer.avro是用于Avro提供数据序列化操作外,其余都是用户Hadoop的I/O操作。
1 I/O操作中的数据检查
校验和方式是检查数据完整性的重要方式。一般会通过
对比新旧校验和来确定数据情况,若两者不同则说明数据已经损坏。
HDFS会对写入的所有数据计算校验和,并在读取数据时验证校验和。
常用的错误检测码是CRC-32(
循环冗余校验)。任何大小的数据输入均计算得到一个32位的整数校验和。
hadoop采用HDFS作为默认的文件系统,需要考虑
两方面的数据完整性:
(1)
对本地文件I/O的检查
在Hadoop中,本地文件系统的数据完整性由
客户端负责。重点在于存车读取文件时进行校验和的处理。
具体做法是:每当hadoop创建文件a时,hadoop就会同时在同一个文件夹下创建隐藏文件.
a.crc,这个文件记录了 文件a的校验和。针对数据文件的大小,每512个字节会生成一个32位的校验和(4字节),可以在src/core/core-default.xml中通过修改io.bytes.per.checksum的大小来修改每个校验和所针对的文件的大小。
在hadoop中,
校验和系统单独为一类---org.apache.hadoop.fs.ChecksumFileSystem,当需要校验和机制时,可以很方便的调用它来服务。
(2)
对HDFS的I/O数据进行检查
一般来说,HDFS会在三种情况下检验校验和:
1)
DataNode接收数据后存储数据前
DataNode接收数据一般有两种情况:一是客户从客户端上传数据;二是DataNode从其他DataNode上接收数据。当客户端上传数据时,Hadoop会根据预定规则形成一条
数据管线。
图7-1(Hadoop实战第二版)是一个典型的副本管线(数据被分为3)。数据0是原数据,数据1,数据2,数据3是 备份。
数据按管线流动以完成数据的上传及备份过程。其数据就是先在客户端这个节点上保存数据,备份1在接收数据的同时也会把接收到的数据发送给备份2所在的机器,若过程顺利,三个备份形成的时间相差不多。
DataNode数据存储步骤:(包括从DataNode和客户端两种传输方式)
Ⅰ:在传输数据的最开始阶段,Hadoop会简单地检查数据块的完整性信息;
Ⅱ:依次向各个DataNode传输数据,包括数据头信息、块信息、备份个数、校验和等;
Ⅲ:Hadoop不会在数据每流动到一个DataNode时都检查校验和,它只会在数据流达到最后一个节点时才检查校验和。
2)
客户端读取DataNode上的数据时
Hadoop会在客户端读取DataNode上的数据时,使用DFSClient中的read函数
先将数据
读入到用户的数据缓冲区,然后
再检查校验和。
3)
DataNode后台守护进程的定期检查
DataNode会在后台运行DataBlockScanner,这个程序会
定期检查此DataNode上的所有数据块。
2 数据恢复
基本思路是:HDFS存储至少三个相同的数据块,假设数据块1,2,3时相同的三个数据块,
①客户端读取数据块1时,检测到数据块1发生了错误,首先向namenode报告数据块1已经损坏;并抛出异常信息;
②namenode将这个数据块1标记成已损坏,所以namenode不会再分配客户端去读取数据块1,而是分配客户端去读取数据块2或者数据块3;
③为了保证正确数据块1的数量不变,会复制数据块2或3到datanode的数据块4中;
④删除已损坏数据块1,这样就保证复本因子的不变。数据块数量为3.
在hadoop上进行数据读操作时,若发现某数据快失效,读操作涉及的用户,DataNode和NameNode都会尝试来恢复数据块,
恢复成功后设置标签,防止其他角色重复恢复。
1)
检查已恢复标签
检查一致的数据块恢复标记,若已经恢复,则直接跳过恢复阶段。
2)
统计各个备份数据块恢复状态
在这个阶段,DataNode会检查所有出错数据块备份的DataNode,查看这些节点上数据块的恢复情况,将其作为一条记录保存在数据块记录表中。
3)找出所有正确版本数据块中最小长度的版本
DataNode会扫描上一阶段中保存的数据块记录,
判断当前副本是否正在恢复;
是:跳过;
否:
判断是否配置参数设置了恢复需要保存原副本长度:
是:将恢复长度相同的副本加入待恢复队列;
否:将所有正确的副本加入到待恢复队列。
4)副本同步
若需要保持副本长度,则直接同步长度相同的副本即可,否则以长度最小的副本同步其他副本。
3 数据压缩
对于任何大容量的分布式存储而言,文件压缩都是必须的,文件压缩带来的
好处是:
Ⅰ:减少文件所需的存储空间;
Ⅱ:加快文件在网络上或磁盘上的传输速率;
hadoop关于文件压缩的代码几乎都在package.org.apache.hadoop.io.compress中。
(1)hadoop对压缩工具的选择
压缩一般是在时间和空间上的一种权衡。一般来说,更长的压缩时间会接生过更多的空间。不同的压缩算法之间有一定的区别。
(2)压缩分割和输入分割
压缩分割和输入分割时很重要的。bzip2支持文件分割,用户可以分开读取每块内容并分别处理之,因此bizip2压缩的文件可分割存储
(3)在MapReduce程序中使用压缩
在MapReduce中使用压缩非常简答,只需在它进行Job配置时配置好conf就可以了。
设置map处理后压缩数据的代码如下:
JobConf conf = new Jobconf();
conf.setBoolean("mapred.compress.map.output",true);
对一般情况,压缩总是好的,无论是对最终结果的压缩还是对map处理后的中间数据进行压缩。
4 数据的I/O中
序列化
操作
序列化是将对象转化为字节流的方法,或者说用字节流描述对象的方法。与序列化相对的是反序列化,反序列化就是将字节流转化为对象的方法。
序列化有两个目的 :
进程间通信;
数据持久性存储;
hadoop采用RPC来实现进程间通信 。一般而言,
RPC的序列化机制有以下特点:
紧凑:紧凑的格式可以充分利用带宽,加快传输速度;
快速:能减少序列化和反序列化的开销;
可扩展性:可以逐步改变,是客户端与服务器端直接相关 的;
互操作性:支持不同语言编写的客户端与服务器交互数据;
在hadoop中,序列化处于核心地位。因为无论是存储文件还是计算中传输数据,都需要执行序列化过程。hadoop并没有采用java提供的序列化机制(java object serialization),而是自己重新写了一个序列化机制Writeables,它具有紧凑,快速的特点,更方便。
(1)Writable类
Writable是hadoop的核心,hadoop通过它定义了hadoop中基础的数据类型和操作。一般来说,无论是 上传下载数据还是运行MapReduce程序,无时无刻不需要使用Writable类,
Writeable类中只定义了两种方法:
序列化输出数据流和
反序列化输入数据流;
或者这样分类:将其状态
写
到DataOutput二进制流
(序列化)
和从DataInput二进制流
读
取状态(
发序列化
);
1)Hadoop的比较器
WritableComparable是Hadoop中的接口类。
在执行MapRedure,我们知道会对key默认的排序输出,就是WritableComparable的功劳。
2)writable类中的数据类型
java基本类;例如:boolean,byte,int,float,long,double(6个)
其他类
NullWritable:这是一个占位符,他的序列化长度为0
BytesWritable和ByteWritable:BytesWritable是一个二进制数据数组的封装;ByteWritable是二进制数据封装
Text:hadoop对string类型的重写,使用标准的UTF-8编码。
可以理解成Java中
String类,
但有一定的区别,例如索引、可变性等;
ObjectWritable:一种多类型的封装。
ArrayWritable和TwoArrayWritable:针对数组和二维数组的构建的数据类型。
MapWritable和SortedMapWritable:分别是java.util.Map()和java.util.SortedMap()的实现。
CompressedWritable:保存压缩数据的 数据结构。
GenericWritable:通用的数据封装类型。
VersionedWritable:一个抽象的版本检查类。
(2)实现自己的hadoop数据类型
hadoop可以支持实现自己的数据类型。
5 序列化框架Avro
尽管大部分MapReduce程序使用的是Writeable类型的key和value,但不是强制使用。可以使用任何类型,只要能有一种机制对每个类型进行类型和二进制表示来回转换。
序列性框架就是解决这种问题,它是用一个Serialization实现来表示,Avro就是一种序列化框架。
6 针对MapReduce的文件类
对于默写应用,需要
特殊的数据结构
来存储自己的数据。针对此需求,hadoop提供了一些更高层次的容器。
hadoop定义了一些文件数据结构以适应Mapreduce编程框架的需要,其中
SequenceFile和MapFile两种类型非常重要。Map输出的中间结果就是由他们表示的,其中,MapFile是经过排序并带有索引的SequenceFile.
(1)SequenceFile类
记录的是key/value对的列表,是
序列化之后的二进制文件,因此不能直接查看,可通过命令查看文件内容。
hadoop fs -text MySequenceFile
sequence有三种不同类型的结构:
未压缩的key/value对;
记录压缩的key/value对(只有value被压缩);
Block压缩的key/value对;
注:未压缩和只压缩value的SequenceFile数据格式,两种数据格式相同。
(2)MapFile类
MapFile的使用与SequenceFile类似,与SequenceFile生成一个文件不同,这个程序生成一个文件夹。
(3)ArrayFile,SetFile和BloomMapFile
ArrayFile继承自MapFile,保存的是从Integer到value的映射关系。
SetFile继承自MapFile,同JAVA的set类似,仅仅是一个key的集合,而没有任何value。
BloomMapFile在实际使用中发挥的作用和MapFile类似,只是增加了过滤功能。
参考文章:
Hadoop实战第二版第七章 (未加粗)
hadoop权威指南第三版第四章(加粗)