第四章之Hadoop I/O

数据的完整性

检测数据是否损坏的常见措施是:在数据第一次引入系统的时候计算校验和(checksum),并在数据通过一个不可靠的通道进行传输时候再次计算校验和,这样就能发现数据是否损坏。如果新的校验和和原来的校验和不匹配,我们就认为数据已经损坏。常用的数据检测码是:CRC-32(循环冗余校验)

HDFS的数据完整性

datanode负责验证收到的数据后存储数据及其校验和,它在收到客户端的数据或复制期间其他datanode的数据时候执行这个操作。正在写数据的客户端将数据极其校验和发送到由一些列datanode组成的管线,管线中的最后一个datanode负责验证校验和。如果datanode检测到错误,客户端变收到一个ChecksumException异常。

客户端从datanode读取数据的时候,也会验证校验和,将他们与datanode中存储的校验和进行比较。每个datanode均持久保存有一个用户验证的校验和日志(persistent log of checksum verification),so他知道每个数据块最后一次的验证时间。客户端成功验证一个数据块以后,会告诉这个datanode,datanode由此更新日志。不只是客户端在读取数据的时候会验证校验和,每个datanode也会在一个后台线程中运行DataBlockScanner,从而定期验证存储在这个datanode上的所有数据块。

 

LocalFileSystem

Hadoop的LocalFileSystem执行客户端的校验和验证。LocalFileSystem通过ChecksumFileSystem来完成自己的任务,有了这个类,向其他文件系统加入校验和就非常简单。

压缩

文件压缩有两大好处:可以减少存储文件所需要的磁盘空间,可以加速数据在网络和磁盘上的传输。需要处理大量数据的时候,这两大好处是相当重要的。

gzip是一个通用的压缩工具。

codec实现了一种压缩--解压缩算法。

通过CompressionCodec对数据流进行压缩和解压缩

 

压缩和输入分片

在考虑如何压缩将由MapReduce处理的数据的时候,理解这些压缩格式是否支持切分(splitting)是非常重要的。gzip并不支持文件切分。

 

在MapReduce中使用压缩

如果输入的文件是压缩的,那么在根据文件扩展名推断出相应的codec后,MapReduce会在读取文件时候自动解压缩文件。

想要对MapReduce作业的输出进行压缩操作,应在配置过程中,把mapred.output.compress属性设置为true和mapred.output.compression.codec

对Map任务输出进行压缩

尽管MapReduce应用读写的是未经过压缩的数据,但是如果对map阶段的中间输入进行压缩,也可以获得不少好处。由于map任务的输出需要写到磁盘并通过网络传输到reducer节点,所以如果使用LZO这样的快速压缩方式,是可以获得性能提升的,因为需要传输的数据减少了。

 

序列化

所谓序列化(serialization)是指将结构化对象转化为字节流,以便在网络上传输或者写到磁盘进行永久存储。

反序列化(deserialization)是指讲字节流转回结构化对象的逆过程。

序列化在分布式数据处理的两大领域经常出现:进程间通信和永久存储。

在Hadoop中,系统中多个节点上进程间的通信是通过“远程过程调用RPC”实现的,RPC协议将消息序列成二进制流之后发送到远程节点,远程节点接着将二进制流反序列化为原始信息。

Hadoop使用自己的序列化格式:Writable,它格式紧凑,速度快,但很难用java以外的语言进行扩展和使用。

Writable接口:

writable接口定义了两个方法:一个讲其状态写到DataOutput二进制流,另一个从DataInput二进制流读取其状态。

 

Writable集合类

在org.apache.hadoop.io包中,有4个Writable集合类:ArriyWritable,TwoDArrayWritable,MapWritable,SortedMapWritable

 

序列化框架

尽管大多数MapReduce程序使用的都是Writable类型的键和值,但这并不是MapReduce强制使用的,事实上可以使用任何类型,只要有一中机制能对每个类型进行类型与二进制的表示的来回切换。

为了支持这一个机制,Hadoop有一个针对可替换序列框架(serialization framework)的API

 

Avro

Apache Avro 是一个独立于编程语言的数据序列化系统,该项目旨在解决Hadoop中Writable类型的不足:缺乏语言的可移植性。

为什么要有一个新的数据序列化系统?与Apache Thrift和Google  的 Protocol Buffers相比,Avro有独特的特性,

Avro数据是用语言无关的模式定义的,但是与其他系统不同的是,Avro的代码生成是可选的,这意味着你可以对遵循指定模式的数据进行读写操作,即使再次之前代码,从来没有见过这个特殊的数据模式,为此,Avro假设数据模式总是存在的。Avro模式通常使用JSON编写,而数据通常用二进制格式编码,但也有其他选择。

 

基于文件的数据结构

对于某些应用而言,需要特殊的数据结构来存储自己的数据,对于基于MapReduce的数据处理,讲每个二进制数据的大对象(blob)融入自己的文件中并不能实现很高的扩展性,所以针对上述情况Hadpp开发了一组更高层次的容器。

SequenceFile  

考虑到日志文件,其中每一条日志记录是一行文本,如果想记录二进制类型,纯文本是不合适的。这种情况下,Hadoop的SequenceFile类非常合适,因为上述类提供了二进制键/值对的永久存储的数据结构。当作为日志文件的存储格式的时候,你可以自己选择键,比如由LongWritable类型表示的时间戳,以及值可以是Writable类型,用于表示日志记录的数量。

SequenceFiles同样可以作为小文件的容器,而HDFS和MapReduce是针对大文件进行优化的,所以通过SequenceFile类型将小文件包装起来,可以获得更高效率的存储和处理。

SequenceFile的写操作,通过createwriteer()静态方法可以创建SequenceFile对象,并返回SequenceFile.Writer实例。存储在SequenceFile中的键和值并不一定需要是Writable类型,任一可以通过Serialization类实现序列化和反序列化的类型均可以被使用。一旦拥有SequenceFile.Writer实例,就可以通过append()方法在文件末尾附加键/值对。写完之后,可以调用close()方法。

SequenceFile读取操作。从头到尾读取顺序文件的过程是创建SequenceFile.Reader实例后反复调用next()方法迭代读取记录的过程。读取的是哪条记录与你使用的序列化框架相关。如果是Writable类型,那么通过键/值作为参数的next()方法可以将数据流中的下一条键值对读入变量中。

 

排序和合并顺序文件

MapReduce是对多个顺序文件进行排序(或者合并)最有效的方法,MapReduce本身具有并行执行能力,并且可以由你指定reducer的数量(该数决定着输出分区数),例如,通过指定一个reducer,可以得到一个输出文件。通过MapReduce实现排序/归并的另一种方法是是用SequenceFile.Sorter类中的sort()方法和merge()方法。

 

顺序文件的格式

顺序文件由文件头和最后的一条或者多条记录组成,顺序文件的前三个字节为SEQ,紧随其后的一个字节表示顺序文件的版本号。文件头还包括其他一些字段,包括键和值相应类的名称,数据压缩细节,用户定义的元数据,以及同步标志。

 

MapFile  

MapFile是已经排序的SequenceFile,他已经加入用于搜索键的索引。

写入MapFile  类似与SequenceFile的写入。读取也是一样类似。在MapFile中搜索就相当于在索引和排过序的SequenceFile中搜索,所以可以把Sequence转换为MapFile。

posted @ 2012-07-28 00:05  honkcal  阅读(701)  评论(0编辑  收藏  举报