一、数据的完整性

由于每个磁盘或者网络上的I/O操作肯能会对正在读写的数据不慎引入错误,如果通过的数据流量非常大,数据发生损坏的几率非常高。

检测损坏数据的常用方法是在第一次进入系统时计算数据的校验和,然后只要数据是在一个不可靠的通道上传输,就可能被损坏。如果新生成的校验和不完全匹配原始的校验和,那么数据就会被认为是被损坏了。这项技术不提供任何方式来修复数据,仅仅是错误检测。(有可能校验和出错,但数据是正确的,但肯能性不大)。

熟悉数据结构或网络编程的同学都知道一种常用的错误检测代码 CRC-32(循环冗余检测),计算一个32位的任何大小输入的整数校验和。


二、HDFS以透明方式校验所以写入它的数据,在默认设置下,会在读取数据时验证校验和。针对每个io.byte.per.checksum字节,都会创建一个单独的校验和。默认值为512字节。当客户端写入数据并且将它发送到一个数据节点的管线中,管线上的最后一个数据节点验证校验和,如果此节点检测到错误,客户端会收到一个Checksum Exception,是IOException的一个子类。如果客户端读取数据块时检测到错误,它在抛出ChecksumException前报告该坏块以及试图从名称节点中读取数据节点,名称节点标记该块已损坏,会从其他副本复制一个新的副本,这样它的副本数就会回归到预期的数量。损坏的副本将被删除。

禁用校验和:

(1)在用open()方法读取文件前,传一个falseFileSystem中的setVerifyChecksum()方法来禁用校验和。

(2)shell命令,如-get,=、-copyToLocal -ignoreCrc等。

(3)底层文件系统原生支持校验和,是通过RawLocalFileSystem 来代替 LocalFileSystem完成的。如果只想针对某些读取禁用校验和,可以创建一个RawLocalFileSystem实例,

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

三、当写入一个名为filename的文件时,文件系统的客户端以透明方式创建一个隐藏的文件.filename.crc,在同一个文件夹下包含每个文件块的校验和。比如HDFS块,大小受io.bytes.per.checksum属性控制,默认为512字节。块的大小作为元数据储存在.crc文件中。读取文件过程中会对校验和进行验证,如果检测到错误,本地文件系统抛出Checksum Exception。


四、ChecksumFileSystem校验和文件系统

继承自FilterFileSystem类,为每个原始文件创建一个校验和文件,这些操作都在客户端完成。它很容易添加到各种文件系统中,如:

FileSyatem rawFs = new LocalFileSystem();
FileSystem checksummedFs = new ChecksumFileSystem(rawFs); //为rawFs创建校验和文件实例

方法:

getRawFilwSystem() //获得原始文件系统
getChecksumFile(Path file) //返回与file相关的校验和文件,后缀名为.crc
isChecksumFile(Path file) //如果file为校验和文件,返回true
reportChecksumFailure(Pathf,FSDataInputStreamin, longinPos,FSDataInputStreamsums, longsumsPos) //向文件系统报告校验错误
setVerifyChecksum(boolean verifyChecksum) //设置是否验证校验
getChecksumLength(longsize, intbytesPerSum) //根据参数字节计算校验和长度