Hadoop 中的I/O (1) 数据检查

原创
2017/02/22 23:37
阅读数 209

I/O操作中的数据检查

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操作。Hadoop的I/O由传统的I/O操作演化而来,但也有所不同。首先,我们常见的计算机系统中,数据是集中的,无论多少电影,音乐,或者文档,它只会存在于同一台主机的同一块硬盘中,而Hadoop则不同,Hadoop系统中的数据经常是分散在多个计算机系统中的;其次传统pc中的数据量相对较小,大多数在GB级别,而Hadoop处理的数据经常是PB级别的。 变化就会带来问题,这两个变化带给我们的问题就是Hadoop的I/O操作不仅仅要考虑本机I/O操作成本,还要考虑数据在不同主机之间的传输成本。同时Hadoop的数据寻址方式也要改变,才能应付庞大的数据带来的寻址压力。

尽管磁盘或网络上的每个I/O操作出现问题的概率很小,但如果系统处理的数据大到Hadoop的处理极限时,数据被损坏的概率还是非常高的。

检测数据最常见的措施是,在数据第一次引入系统时计算校验和(checksum)并在数据通过一个不可靠的通道进行传输时再次计算校验和,这样就能发现数据是否损坏。如果发现错误,该技术并不能进行修复。(校验和也可能是损坏的)常见的错误校验码是CRC-32(循环冗余校验),任何大小的数据输入均计算得到一个32位的整数校验和。

1. HDFS 的数据完整性

HDFS会对写入的所有数据计算校验和,并在读取数据时验证和。它针对每个由 io.bytes.per.checksum 指定字节的数据计算校验和。默认情况下为512个字节,由于CRC-32校验和是4字节,所以存储校验和的开销低于1%。 datanode负责在收到数据后存储该数据以及验证校验和。它在收到客户端的数据或者复制其它datanode的数据时执行这个操作,正在写数据的客户端将数据和校验和发送到由一系列datanode组成的管线,管线中的最后一个datanode负责计算校验和。如果datanode检测到错误,客户端便会收到一个ChecksumException异常,它是IOException异常的一个子类,后者应以应用程序特定的方式来处理,比如重试这个操作。 客户端从datanode读取数据时,也会验证校验和,将他们与datanode中存储的校验和进行比较。每个datanode均永久保存一个用于验证的校验和日志(persistent log of checksum verifaction),所以它知道每个数据块的最后一次验证时间。客户端成功验证了一个数据块后,会告诉这个datanode,datanode由此更新日志。保存这些信息对检测损坏的磁盘很有价值。 不只是客户端在读取数据块时会验证校验和,每个datanode也会在后台运行一个DataBlockScanner,从而定期验证存储在这个datanode上的所有数据块。该项措施是解决物理存储媒体上位损坏的有力措施。 由于DFS存储着每个数据快的副本(replica),因此它可以通过数据副本来修复这些损坏的数据块,进而得到一个新的,完好无损的副本。基本思路是:客户端在读取数据时,如果检测到错误,首先向namenode已损坏的数据块及其正在尝试读操作的这个datanode,在抛出ChecksumException异常。namenode将这个数据块的副本标记为已损坏,然后不会将处理请求直接发送到这个节点,或尝试将这个副本复制到另一个datanode。之后它安排这个数据块的一个副本复制到另一个datanode,如此一来数据块的副本因子(replication factor)又回到了期望的水平。此后,已损坏的数据块副本便被删除。 在使用open() 方法读取文件之前,将false值传给 FileSystem 对象的 setVerifyChecksum() 方法,即可以禁用校验和验证。如果在命令行中使用带 -get 选项的 -ignoreCrc 命令或者使用等价的 -copyToLocal 命令也可以达到同样的效果。如果有一个已损坏的文件需要检查并决定如何处理,那么这个特性就会是非常有用的。例如,或许你希望在删除文件之前尝试看看能否恢复部分数据。

2. LocalFileSystem

Hadoop的 LocalFileSystem 执行客户端的校验和验证。如果你需要写一个名为 a 的文件,文件系统客户端会明确的在包含每个文件块校验和的同一个目录内新建一个名为 a.crc 的隐藏文件。如同HDFS的校验机制,文件块的大小由 io.bytes.per.checksum 控制,默认为512个字节。文件块的大小作为元数据存储在.crc文件中,所以即使文件块的大小设置已经发生了变化,仍然可以正确的读回文件。在读取文件时需要验证校验和,如果检测到了错误,LocalFileSystem 会抛出 ChecksumException。 校验和计算的代价是相当低的(java使用本地方法来实现校验和计算),其消耗一般只是增加了少许额外的I/O。如果底层文件系统本身就支持校验和的时候,我们还可以选择使用 RawLocalFileSystem 替代 LocalFileSystem 来实现禁用校验和计算。如果需要在一个应用中实现全局校验和验证,那就要将 fs.file.impl 属性设置为 org.apache.hadoop.fs.RawLocalFileSystem 进而来实现URI的重新映射。还可以通过直接新建一个 RawLocalFileSystem 的方式来实现对一些读操作禁用校验和,实例如下:

    Configuration conf;
    FileSystem fs = new RawLocalFileSystem();
    fs.initialize(null,conf);

3. ChecksumFileSystem

LocalFileSystem 通过 ChecksumFileSystem 来完成自己的任务,有了这个类向其它文件系统(无校验和系统)加入校验和就非常简单,因为 LocalFileSystem 是 ChecksumFileSystem 的子类。

LocalFileSystem结构图

底层文件系统称为“源”(raw)文件系统,可以使用 CkecksumFileSystem 实例的 getRawFileSystem() 方法来获取它。 ChecksumFileSystem 类还有一些其它和校验和有关的方法如 getCkecksumFile() 可以获取任意文件的校验和的文件路径。具体使用方法请参照API。 如果 ChecksumFileSystem 类在读取文件时发生了错误,就会调用自身的 reportChecksumFailure() 方法,该方法默认的实现为空,但 LocalFileSystem 类会将这个出错的文件及其校验和移动到同一设备上一个名为 bad_files 的边际文件夹(side directory)中。管理员应定期检查这些坏文件并作出相应的处理。

展开阅读全文
打赏
0
2 收藏
分享
加载中
更多评论
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部