9、Hadoop的I/O

1、数据完整性

Hadoop的用户当然希望数据在磁盘I/O或网络传输时不发生丢失或损坏。但是通过的数据流量非常大,数据发生损坏的几率还是很大的。

HDFS的数据完整性:HDFS以透明方式校验所有写入它的数据,并在默认设置下,会在读取数据时验证校验和。数据节点负责在存储数据及其校验和前验证它们收到的数据。客户端读取数据节点上的数据时,会验证校验和,将其与数据节点上的校验和对比。

Hadoop本地文件系统:Hadoop本地文件系统执行客户端校验。这意味着在写一个filename文件时,本地文件系统的客户端以透明的方法创建了隐藏文件filename.crc,在同一个文件夹下包含每个文件块的校验和。LocalFileSystem使用ChecksumFileSystem(校验和文件系统)为自己工作。

2、压缩(可以参考我的另一篇文章点击打开链接

CompressionCodec有两个方法用于压缩或解压缩数据:

CompressionInputStream createInputStream(InputStream in) throws IOException
CompressionOutputStream createOutputStream(OutputStream out) throws IOException
另外,压缩格式是否支持分割很重要。对于存储在HDFS中的未压缩的1GB文件,如果块大小为64MB,那么该文件可以分割成16块,以该文件作为输入的MapReduce作业会创建16个输入分片,每个分片都被作为一个独立的map任务的单独输入进行处理。但是如果该文件是gzip格式的压缩文件(gzip不支持分割机制),一个map任务将处理16个HDFS块,因为map任务少,所以作业的分割粒度不够细,运行时间变长。那么在实际运用中如何使用压缩格式: 1)存储未压缩的文件;2)使用支持分割的压缩格式(如bzip2);3)在应用中将文件分割成几个大的数据块,然后对每个数据块单独压缩;4)使用支持压缩和分割的序列文件(sequence file)。

2、序列化(可参考另一篇文章点击打开链接

2.1、Writable接口

Writable接口定义了两个方法:一个用于其状态写入的二进制格式的DataOutput流,另一个用于从二进制格式的DataInput流中读取其状态:

void write(DataOutput out) throws IOException
void readFields(DataInput in) throws IOException
IntWritable、LongWritable等都是实现了WritableComparable接口,后者是Writable和java.lang.Comparable接口的子接口:

public interface WritableComparable<T> extends Writable, Comparable<T>{
}
类型的比较对于MapReduce而言至关重要,键与键的比较是在排序阶段完成的。Hadoop提供的一个优化方法是从java Comparator的RawComparator的扩展:

public interface RawComparator<T> extends Comparator<T>
{
    public int compare(byte[] b1,
            int s1,
            int l1,
            byte[] b2,
            int s2,
            int l2);
}
这个接口允许执行者比较从流中读取未被反序列化对象的记录,从而省去了创建对象的开销。例如,IntWritable的comparator使用RawComparator中compare()方法进行比较就是从每个字节数组的指定开始位置(s1和s2)和长度(l1和l2)读取整数b1和b2后直接进行比较。WritableComparator是RawComparator对WritableComparable类的一个通用实现。它主要提供两个功能:1)提供了一个默认的对原始compare()的调用;2)充当的是RawComparator实例的一个工厂方法。例如,为获得IntWritable的comparator,只需要:

RawComparator<IntWritable> comparator = WritableComparator.get(IntWritable.class);//comparatpr可以用来比较两个IntWritable对象:
IntWritable w1 = new IntWritable(163);
IntWritable w2 = new IntWritable(67);
assertThat(comparator.compare(w1,w2),greaterThan(0));
2.2、Writable类
目前所有Writable的java基本类的封装有:BooleanWritable(1字节)/ByteWritable(1)/IntWritable(4)/VIntWritable(1-5)/FloatWritable(4)/LongWritable(8)/VLongWritable(1-9)/DoubleWritable(8),其中char和short类型均可存储在IntWritable中。它们都有用于检索和设置值的get()和set()方法。

1)Text类:Text类是一种UTF-8格式的Writable,可以将它理解为java.lang.String相类似的Writable。Text类的索引位于编码后的字节序列中,而不是字符串中Unicode字符或java中char的编码单元。
2)BytesWritable是一个二进制数据数组封装。它序列化的格式是一个int字段(4字节),指定的是字节数和字节本身。

3)NullWritable:是一种特殊的Writable类型,因为它的序列化是零长度,没有字节被写入流或从流中读出。被用作占位符。

4)ObjectWritable和GenericWritable

5)Writable集合:ArrayWritable、TwoDArrayWritable、MapWritable和SortedMapWritable
3、基于文件的数据结构

3.1、SequenceFile类为二进制键/值提供一个持久化的数据结构。

想要新建一个SequenceFile类,使用其中一个静态方法createWriter(),它会返回一个SequenceFile.writer实例。有几个重载版本,但是都需要指定一个要写入的流(FSDataInputStream或成对的文件系统和路径),一个Configuration对象和键/值类型,可选类型还包括压缩类型和编码/解码器,一个将由写进度来唤醒的Progressable的回调和一个将存储在SequenceFile头部的MetaData实例。

序列文件的格式:序列文件是由头部和一个或多个记录组成。(图参考至点击打开链接

1)无压缩序列文件格式


2)记录压缩的序列文件格式


3)块压缩的序列文件格式


3.2、MapFile

MapFile是经过排序的带索引的SequenceFile,可以根据键进行查找。写一个MapFile和写一个SequenceFile差不多:创建一个MapFile.Writer的实例,然后调用append()方法,按顺序增加 条目。读取过程也很类似:创建一个MapFile.reader,然后调用next()方法直到它返回false,表示没有条目可以再读取因为已经到达文件末尾。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值