Hadoop I/O By ShiChaojie
index 数据完整性 1 2 3 4 压缩 序列化 基于文件的数据结构
Introduction 所谓I/O,通俗的讲就是:利用接口等处理不同输入输出信息。 Hadoop自带一套原子操作用于数据I/O。其中一些技术比较常用,如数据完整性保持与压缩。 另一些则是基于Hadoop工具或者API,它们所形成的构建模块可用于开发分布式系统,比如序列化操作和在盘(on-disk)数据结构。 对于多达几个TB的数据集,这些方法特别值得关注。
数据完整性 目的: 用户希望系统在存储和处理数据时,数据不会有任何损失 或丢失。 现实: Hadoop对硬件要求不高,硬件故障。 系统需要处理的数据达到Hadoop能够处理的极限时,数 据被破坏的概率还是很高的 方案: 引入校验和(checksum)的概念:在数据第一次引入系 统时计算效验和通过不可靠通道传输时再次计算校验和。 校验和无法修复数据,因此推荐使用ECC内存。 CRC-32(循环冗余校验)
数据完整性—HDFS HDFS会对写入的所有数据计算校验和,并在读取数据时验证校验和。它针对每个由io.bytes.per.checksum指定字节的数据计算校验和。(512Bytes CRC32) datanode负责在验证收到数据后存储数据及其校验和。 客户端从datanode读取数据时,也会验证校验和,将它们与datanode中存储的校验和进行比较。 此外,每个datanode也会在后台线程中运行一个DataBlockScanner,定期验证存储在这个datanode上所有的数据块。 HDFS文件系统存储着每个数据块的副本,通过复制完好的数据副本可以修复损坏的数据块。
数据完整性—LocalFileSystem Hadoop的LocalFileSystem执行客户端的校验和验证。当写入名为filename的文件时,文件系统客户端会明确地在包含每个文件块校验和同一个目录内新建一个名为.filename.crc 的隐藏文件。 就像HDFS一样,文件块的大小由属性io.bytes.per.checksum控制,控制,默认为512bytes。 在读取文件时需要验证校验和,检测到错误,LocalFileSystem将抛出一个ChecksumException异常。 校验和的计算代价是相当低的。
数据完整性—ChecksumFileSystem LocalFileSystem通过ChecksumFileSystem完成校验,有了该类,其他文件系统(无校验和系统)加入校验和就变的相当简单,ChecksumFileSystem类继承自FileSystem类。一般用法如下: Configuration conf = … FileSystem fs = new RawLocalFileSystem(); Fs.initialize(null , conf);
压缩 压缩的好处:可以减存储文件所需要的磁盘空间;可以加速数据在网络和磁盘上的传输。 常见的压缩格式:
压缩-codec Codec实现了一种压缩-解压缩算法。Hadoop中,一个对CompressionCodec接口的实现代表一个codec。所以GzipCodec包装了gzip的压缩和解压缩算法。 Hadpoop实现的codec:
压缩-CompressionCodec CompressionCodec接口包含两个函数,可以用于压缩和解压数据。 对写入输出数据流的数据进行压缩,可用createOutputStream(OutputStream out)方法在底层的数据流中对需要以压缩格式写入在此之前尚未压缩的数据新建一个CompressionOutputStream对象。 对输入数据流中读取的数据进行解压缩的时候,调用createInputStream(InputStream in)获取CmpressionInputStream,通过该方法从底层数据流读取解压缩后的数据。
压缩-CompressionCodec 该程序压缩从标准输入读取的数据,然后将其写到标准输出。
压缩-CompressionCodecFactory 若文件以.gz结尾,则可以用GzipCodec来读取。 通过使用getCodeC()方法, CompressionCodecFactory提供了一种方法将文件名映射到一个CompressionCodec,改方法读取文件的Path对象作为参数。
压缩-原生类库 为了性能,最好使用“原生”(naive)类库来实现压缩和解压缩。 在测试中,使用原生gzip类库可以减少大约一半的解压缩时间和大约10%的压缩时间(与内置的java实现)。 下表给出了每种压缩格式的java实现和原生类库实现: Codecpool:如果使用原生代码库并且在应用中执行大量的压缩和解压缩操作,可以使用Codecpool,它允许反复使用压缩和解压缩,以分摊创建这些对象所涉及的开销。
压缩-压缩和输入分片 压缩将由MapReduce处理的数据时,压缩格式是否支持切片(splitting)是非常重要的。
压缩-在MapReduce中使用压缩 如果输入文件是压缩的,根据文件扩展名推断出相应的codec后,MapReduce会在读取时文件时自动解压缩文件。 对MapReduce作业的输出进行压缩,应在祖业配置过程中,将mapred.output.compress属性设置为true和mapred.output.compression.codec属性设置为打算使用的压缩codec的类名。
压缩-在MapReduce中使用压缩 为生顺序文件(sequence file),可以设置mapred.output.compression.type属性来控制要使用哪种压缩格式。 默认值是RECORD,即针对每条记录进行压缩。(BLOCK 、压缩效率高)
压缩-在MapReduce中使用压缩 对map阶段的中间输如进行压缩,可以获得不少好处。 在作业任务中启用map任务输出gzip压缩格式的代码:
序列化 所谓序列化(serialization),是指将结构化的对象转化为字节流,以便在网络上传输或写到磁盘进行永久存储。 反序列化( deserialization )是指将字节流转回到结构化对象的逆过程。 领域:进程间通信和永久存储。 Hadoop中,系统的多个节点上的进程间的通信是通过“远程过程调用(RPC)”实现的,远程节点将二进制流反序列化为原始信息。 RPC格式: 紧凑、快速、可扩展、互操作 Hadoop使用自己的序列化格式Writable,它格式紧凑、速度快,但很难用Java以外的语言进行扩展或使用。
序列化-Writable接口 writable接口定义了两个方法: 1. 将其状态写到DataOutput二进制流 2.从DataInput二进制流读取其状态
序列化-Writable接口 用途: 使用Inwritable封装一个Java int 在序列化对象捕捉字节流
序列化-Writable接口 用途: 反序列化(从一个字节数组中读取一个Writable对象): deserialize()函数读取数据,原始值为163
序列化-WritableComparable 和 comparator 该接口实现了比较数据流的记录,而无需把数据流反序列化为对象(好处)。 comparator实现了compare()方法。 WritableComparator提供了连个主要功能。第一:提过了对原始compare()方法的一个默认实现。第二,充当RawComparator实例的工厂。
序列化-Writable类 Hadoop自带的org.apache.hadoop.io包自带广泛的Writable类供选择 层次结构图:
序列化-java基本类型的Writable类
序列化-java基本类型的Writable类 对整数的编码 Example:值163需要两个字节
序列化-java基本类型的Writable类 Text类型: ByteWritable类型: NullWritable类型: Writable集合类:
序列化-序列化框架 尽管多数MapReduce都使用Writable类型的键和值,但并非MapReduce API强制使用的。 事实上,只要有一种机制支持对每个类型进行类型与二进制表示的来回转换即可。 为了支持这一机制,Hadoop有一个针对可替换序列化框架(serialization framework) Why not java serialization?
序列化-Avro 旨在解决Hadoop中Writable类型的不足:缺乏语言的可移植性