第七章 I/O操作

Hadoop中的I/O与传统I/O的区别:

1、传统I/O数据是集中存储的,在一台主机上,Hadoop I/O数据分布在多台主机上。

2、传统I/O数据量比较小,大多GB级,Hadoop I/O数据量经常PB级的

7.1 I/O操作的数据检查

通过校验和方式检查数据完整性,检验和不恩那个恢复数据,只能检测数据错误。

Hadoop采用CRC-32(检验和为32位)的方式检查数据完整性。

本地文件文件I/O的检查

当Hadoop创建一个文件,同时也会创建一个“文件名.src”的隐藏文件用来保存校验和。例如创建A文件同时也会创建一个A.src的文件用来保存校验和信息。每512byte Hadoop会生成一个32为的校验和(4byte)。这个值可以在

src/core/core-default.xml

 文件中进行修改每个校验和所针对的文件大小

<property>
  <name>io.bytes.per.checksum</name>
  <value>512</value>
  <description>The number of bytes per checksum.  Must not be larger than
  io.file.buffer.size.</description>
</property>

 校验和操作类为

org.apache.hadoop.fs.ChecksumFileSystem

 继承结构如下,是FileSystem的子类


第七章 I/O操作
如果ChecksumFileSystem检测到错误会把源文件、校验和文件移到次级目录bad files中。

本地文件的数据完整性有客户端负责,Hadoop在存储和读取文件时进行校验和处理。

HDFS的I/O数据检查

HDFS会在三种情况下检查校验和

1)DataNode接受数据后存储数据前

DataNode一般在两种情况下接收数据:

用户从客户端上传数据
DataNode从其它DataNode上接收数据
2)客户端读取DataNode上的数据时
当客户端读取DataNode数据时,使用

org.apache.hadoop.hdfs.DFSClient

 中的

/* FSInputChecker interface */
    
    /* same interface as inputStream java.io.InputStream#read()
     * used by DFSInputStream#read()
     * This violates one rule when there is a checksum error:
     * "Read should not modify user buffer before successful read"
     * because it first reads the data to user buffer and then checks
     * the checksum.
     */
    @Override
    public synchronized int read(byte[] buf, int off, int len) 
                                 throws IOException {
      
      //for the first read, skip the extra bytes at the front.
      if (lastChunkLen < 0 && startOffset > firstChunkOffset && len > 0) {
        // Skip these bytes. But don't call this.skip()!
        int toSkip = (int)(startOffset - firstChunkOffset);
        if ( skipBuf == null ) {
          skipBuf = new byte[bytesPerChecksum];
        }
        if ( super.read(skipBuf, 0, toSkip) != toSkip ) {
          // should never happen
          throw new IOException("Could not skip required number of bytes");
        }
      }

 函数,现将数据读入到客户端的数据缓冲区中,然后在检查校验和。

3)DataNode后台守护进程的定期检测
DataNode的后台进程会定期的检查DataNode上的所有数据块

数据恢复策略

 P123

7.2 数据的压缩

Hadoop提供的压缩格式


第七章 I/O操作
 如果需要处理Gzip压缩后的5GB数据,Hadoop本应按64MB为一个数据块进行分割为80份,但Hadoop不会分割压缩后的数据。但如果是bzip2数据,因为它支持分割,所以压缩数据可以分割存储。

在MapReduce程序中使用压缩,设置Map处理后的压缩数据程序如下


第七章 I/O操作
 

7.3 数据的I/O中序列化操作

 序列化:将对象转化为字节流的方式

反序列化:将字节流转换为对象的方式

Writable是Hadoop序列化的核心接口

public interface Writable {
  /** 
   * Serialize the fields of this object to <code>out</code>.
   * 
   * @param out <code>DataOuput</code> to serialize this object into.
   * @throws IOException
   */
  void write(DataOutput out) throws IOException;

  /** 
   * Deserialize the fields of this object from <code>in</code>.  
   * 
   * <p>For efficiency, implementations should attempt to re-use storage in the 
   * existing object where possible.</p>
   * 
   * @param in <code>DataInput</code> to deseriablize this object from.
   * @throws IOException
   */
  void readFields(DataInput in) throws IOException;
}

Hadoop的比较器

WritableComparator是WritableComparable的比较器,它是RawComparator针对WritableComparable的通用实现,RawComparator继承自Comparator。


第七章 I/O操作
 RawComparator中实现了对未反序列化数据的比较,这样可以不必创建对象,直接针对数据的字节流进行比较。

Writable类中的数据类型

 
第七章 I/O操作
 

7.4 对对MapReduce的文件类

 P139 为完成