一、简述
Hadoop的HDFS和MapReduce子框架主要是针对大数据文件来设计,不适合于小文件的存储与处理,这里的小文件主要是size远小于一个block size(默认64M)的文件。为什么呢?首先,每一个小文件都要占用一个block(默认64M),会造成大量磁盘空间的浪费;其次,小文件越多,对namenode的内存压力就越大。
面对这样的情况,我们需要提供小文件整理容器,将这些小文件组织起来统一存储。对此,HDFS支持两种类型的容器,分别是SequenceFile和MapFile,其中MapFile主要是SquenceFile的排序。
二、描述
SequenceFile是通用的KV数据存储格式, 并且key和value都是变长的二进制数据。与其他的key/value数据结构(B-Trees)相比,我们不能通过指定键对SequenceFile文件进行删除、编辑和查找,只支持append操作。
![](https://www.cloudera.com/wp-content/uploads/2011/01/squenceFileHeader.png)
在SquenceFile的三种可用格式中,通过观察得知,非压缩和Record压缩格式十分相似。每次调用append()方法就会添加一条记录到SequenceFile文件中,这条记录包含了整个数据的长度(key长度+value长度)、key长度、key和value行数据。非压缩数据与压缩数据的区别主要在于行数据是否压缩以及压缩所使用的编解码方式。
与Record压缩相比,Block压缩方式更加直接。当压缩数据量达到某一阈值(比如64M)的时才会被写入,它会把所有的键和值分别压缩到一起,然后标注键和值数据的长度。
从“Block”的图中,我们可以看到Block记录包含一个VInt数据来表示记录数据的数量,接着依次是:Keys列表长度、Keys列表数据、Values数据长度、Values列表数据。并且在每个Block之前会加入一个同步标记。
2、Hadoop SequenceFile是其他文件类型的基础数据结构,诸如MapFile、SetFile、ArrayFile和BloomMapFile。
MapFile是一个目录,它包含两个SequenceFile:数据文件(“/data”)和索引文件("/index")。这些数据包含了所有的键、值数据,keys的内容按从小(Key N)到大(Key N+1)的顺序排列,一旦排列出现其他情况,将会抛出IOException“Key out of order”异常。
![](https://www.cloudera.com/wp-content/uploads/2011/01/index-data-bloom.png)
索引文件每行记录了key和索引文件起始位置(LongWritable类型)的字节数据。索引文件记录了一部分keys数据,并没有全部记录,但你可以指定索引间
隔来调用setIndexInterval()函数。通常,索引文件数据会被全部读入内存,如果索引很大,可以设定每次读入内存的索引数量。
SetFile和ArrayFile则基于MapFile,它们的实现仅仅只需要几行代码。当value为NullWritable实例时,SetFile会用append(key)替换append(key, value);而ArrayFile只会用append(value)来添加数据,它的key(LongWritable )按value数据进行逐条递增(1...N+1)。BloomMapFile是在MapFile基础上扩充了一个名叫“/bloom”的文件,这个文件包含新增记录后DynamicBloomFilter的序列化值,在执行文件关闭操作的时候写入。
如果你想了解SequenceFile,MapFile,SetFile,ArrayFile在java以外的应用,我用python实现了一个原生的模块,在我的git仓库 python-hadoop中可以找到。
3、序列化及Writable
(1)、序列化:将对象转化为字节流的方法,达到方便进程间通信以及数据持久性存储的目的。在Hadoop中,序列化在文件存储、数据传输中具有广泛的应用。因此,序列化与反序列化速度、序列化数据大小等都会影响数据存储、数据传输、数据处理。基于此,Hadoop重新设计了一个序列化机制Writables,它具有紧凑、快速的优点,缺点是不易扩展、不利于不同语言间互操作。
(2)、Writable:Hadoop核心的一部分,定义了Hadoop基本数据类型及相关操作,无论数据传输、数据存储,还是数据计算都会频繁用到它,借用网上的一张数据类型结构图,可以看到数据之间的关系:
我们可以通过上面的图看到,其中有WritableComparable和WritableComparator两个类型,而WritableComparator是WritableComparable的比较器,在MapReduce执行作业时,Mapper有一个key排序操作,Reducer会统计相同key对应的key/value对,这些键值的比较都是通过WritableComparator类型进行比较,可见上述两个类型在MapReduce执行作业中的重要性。
4、其他数据类型
Text、NullWritable、ObjectWritable、GenericWritable、ArrayWritable、自定义类型...,我在此只做了一个了解,就不一一描述。