Hadoop的IO操作--校验和-文件结构-数据类型-压缩

一、数据完整性

  用户希望储存和处理数据的时候,不会有任何损失或者损坏。Hadoop提供两种校验:校验和、运行后台程序来检测数据块

1、校验和(常用循环冗余校验CRC-32)

①写入数据节点验证

     --Hdfs会对写入的所有数据计算校验和,并在读取数据时验证校验和。

     --元数据节点负责在验证收到的数据后,储存数据及其校验和。在收到客户端数据或复制其他datanode的数据时执行。

    -- 正在写数据的客户端将数据及其校验和发送到一系列数据节点组成的管线,管线的最后一个数据节点负责验证校验和

②读取数据节点验证

--客户端读取数据节点数据也会验证校验和,将它们与数据节点中储存的校验和进行比较。

---每个数据节点都持久化一个用于验证的校验和日志。客户端成功验证一个数据块后,会告诉这个数据节点,数据节点由此更新日志。

③恢复数据

--由于hdfs储存着每个数据块的备份,它可以通过复制完好的数据备份来修复损坏的数据块来恢复数据。

④Localfilesystem类

HadoopLocalFileSystem类是用来执行客户端的校验和验证。当写入一个名为filename的文件时文件系统客户端会在包含文件块校验和的同一目录内建立一个名为Filename.crc的隐藏文件。

⑤ChecksumfileSystem类

--LocalFileSystem类通过ChecksumFileSystem类来完成自己的任务FileSystemrawFs

--FileSystemchecksummedFs=newChecksumFileSystem(rawFS);可以通过CheckFileSystemgetRawFileSystem()方法获取源文件系统。

--当检测到错误,CheckFileSystem类会调用reportCheckSumFailure()方法报告错误,然后LocalFileSystem将这个出错的文件和校验和移到名为bad_files的文件夹内,管理员可以定期检查这个文件夹。

二、数据结构

基于文件的数据结构

    HDFSMR主要针对大数据文件来设计,在小文件处理上效率低.解决方法是选择一个容器,将这些小文件包装起来,将整个文件作为一条记录,可以获取更高效率的储存和处理,避免多次打开关闭流耗费计算资源.hdfs提供了两种类型的容器SequenceFileMapFile

    Sequence file由一系列的二进制key/value组成,如果key为小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。Hadoop-0.21.0版本开始中提供了SequenceFile,包括WriterReaderSequenceFileSorter类进行写,读和排序操作。该方案对于小文件的存取都比较自由,不限制用户和文件的多少,支持Append追加写入,支持三级文档压缩(不压缩、文件级、块级别)。其存储结构如下图所示:

Hadoop的IO操作--校验和-文件结构-数据类型-压缩

SequenceFile储存

文件中每条记录是可序列化,可持久化的键值对,提供相应的读写器和排序器,写操作根据压缩的类型分为3

Write无压缩写数据
RecordCompressWriter记录级压缩文件,只压缩值
BlockCompressWrite块级压缩文件,键值采用独立压缩方式

在储存结构上,sequenceFile主要由一个Header后跟多条Record组成,

Hadoop的IO操作--校验和-文件结构-数据类型-压缩

   前三个字节是一个Bytes SEQ代表着版本号,同时header也包括key的名称,value class , 压缩细节,metadata,以及Sync markersSync markers的作用在于可以读取任意位置的数据

     在recourds,又分为是否压缩格式。当没有被压缩时,keyvalue使用Serialization序列化写入SequenceFile。当选择压缩格式时,record的压缩格式与没有压缩其实不尽相同,除了valuebytes被压缩,key是不被压缩的

    当保存的记录很多时候,可以把一串记录组织到一起同一压缩成一块Block,它使所有的信息进行压缩,压缩的最小大小由配置文件中,io.seqfile.compress.blocksize配置项决定

SequenceFile操作

通过createWrite创建SequenceFile对象,返回Write实例,指定待写入的数据流如FSDataOutputStreamFileSystem对象和Path对象。还需指定Configuration对象和键值类型(都需要能序列化)

SequenceFile通过API来完成新记录的添加操作

fileWriter.append(key,value);

MapFile

MapFile可以通过SequenceFile的地址,进行分类查找的格式。使用这个格式的优点在于,首先会将SequenceFile中的地址都加载入内存,并且进行了key值排序,从而提供更快的数据查找

SequenceFile只生成一个文件不同,MapFile生成一个文件夹

索引模型按128个键建立的,可以通过io.map.index.interval修改

缺点

1.文件不支持复写操作,不能向已存在的SequenceFile(MapFile)追加存储记录
2.write流不关闭的时候,没有办法构造read流。也就是在执行文件写操作的时候,该文件是不可读取的

Hadoop的IO操作--校验和-文件结构-数据类型-压缩

排序后的SequeneceFile,并且它会额外生成一个索引文件提供按键的查找.读写mapFile与读写SequenceFile

非常类似,只需要换成MapFile.ReaderMapFile.Writer就可以了。

在命令行显示mapFile的文件内容同样要用 -text

两者的区别:

SequenceFile文件是用来存储key-value数据的,但它并不保证这些存储的key-value是有序的

MapFile文件则可以看做是存储有序key-valueSequenceFile文件

MapFile文件保证key-value的有序(基于key)是通过每一次写入key-value时的检查机制,这种检查机制其实很简单,就是保证当前正要写入的key-value与上一个刚写入的key-value符合设定的顺序

但是,这种有序是由用户来保证的,一旦写入的key-value不符合key的非递减顺序,则会直接报错而不是自动的去对输入的key-value排序

SequenceFile转换为MapFile

mapFile既然是排序和索引后的SequenceFile那么自然可以把SequenceFile转换为MapFile使用mapFile.fix()方法把一SequenceFile文件转换成MapFile

三、数据类型

Hadoop定义了两个序列化相关接口

WritableComparable

WritableComparable接口相当于继承了上述两个接口的新接口 

Public interfaceWritableComparable<T>

 extendsWritable,Comparable<T>

Writable接口

基于DataInputDatOutput的简单高效可序列化接口,就是org.apache.hadoop.io.Writable接口

几乎所有的hadoop可序列化对象都必须实现这个接口有2方法

WritereadFiles

IntWritable为例,它把javaint类型封装成了Writable序列化格式

可以通过set()设置它的值 

new IntWritable().set(100);

new IntWritable(100);

WritableComparable接口

类似javaComparable接口,用于类型的比较。MR其中一个阶段叫排序,默认使用Key来排序。Hadoop提供了一个优化接口RawComparator

 Public interfaceRawComparator<T> extendsComparator<T>{

  Publicint compare(byte[]  b1,int s1,int l1,byte[] b2,int s2,int l2);

}

可以比较b1b2,允许执行者直接比较数据流记录,而无须先把数据流反序列化成对象,这样可以避免新建对象的开销

Writable

ArrayWritable

TwoDArrayWritable

MapWritable

SortedMapWritable

BooleanWritable

ByteWritable

IntWritable

VIntWritable

FloatWritable

LongWritable

VLongWritable

DoubleWritable

NullWritable

Text

BytesWritable

MD5Hash

ObjectWrtiable

GenericWritable

Text  

存储的数据按照UTF-8,类似String,它提供了序列化,反序列化和字节级别比较的方法。Text类替换了UTF8类。

1.unicode编码是一个很大的集合,可以容纳100多万个符号。具体的符号对应表可以查询unicode.org它只规定了符号的二进制代码,没有规定如何存储,而utf-8就是unicode的实现还有utf16等。对于单个字符字节第一位为0,后面7位为这个符号的unicode码。因此对于英语字母,utf-8编码和ASCII码是相同的。所有\u0001~\u007f会以单字节储存。\u0080~\u07ffunicode会以双字节储存,\u0800~\uFFFF的会以3字节存储

2.例子Text的几个方法 一旦使用多字节编码TextString区别就明显

Public void testText() throwsUnsupportedEncodingException{

T=new Text(“你好刘老”);

S=”你好刘老”;

assertEquals(t.getLength(),12);

assertEquals(s.getBytes(“utf-8”).length,12);

assertEquals(s.length(),4);

assertEquals(t.find(“”),6);

assertEquals(s.indexOf(“”),3);

}

Text.find()方法返回的是字节偏移量,String.indexOf返回单个编码字符的索引位置,

String.codeprintAt()Text.charAt类似,前者通过字节偏移量来索引

Text对字符串没有String方法丰富 大多数情况下通过toString转换成String来操作

BytesWritable

相当于二进制数据数组的包装。以字节数组{1,2,3,4}它的序列化格式是4字节表示字节数 ,每2个字节表示一个数据即“0000 0004 0102 0304” Text一样BytesWritable也是可变的 ,可以通过set来修改

NullWritable

writable类型的特殊类型,序列化长度为0,它充当占位符但不真在数据流中读写。NullWritable是单实例类型,通过NullWriable.get()方法获取

四、压缩

减少储存文件所需空间,还可以降低其在网络上传输的时间。

压缩算法对比

 算法   原始文件大小     压缩后文件大小 压缩速度   解压缩速度

Gzip               8.3G       1.8G          17.5MB/s      58MB/s

Bzip2                1.1           2.4MB/s       9.5MB/s

LZO-bset                       2             4MB/s        60.6MB/s

LZO                           2.9            49.3MB/s     74.6MB/s

 Bzip2支持切分splitting.hdfs上文件1GB,如按照默认块64MB,那么这个文件被分为16个块。如果把这个块放入MR任务 ,将有16map任务输入。如果算法不支持切分,后果是MR把这个文件作为一个Map输入。这样任务减少了,降低了数据的本地性。

1.CodeC

实现了一种压缩解压算法。Hadoop中压缩解压类实现CompressionCodec接口

createOutputStream来创建一个CompressionOutputStream,将其压缩格式写入底层的流

演示HDFS上一个1.bzip2算法压缩的文件解压,然后把解压的文件压缩成2.gz

2.本地

Hadoop使用java开发,但是有些需求和操作并不适合java,所以引入了本地库 native。可以高效执行某些操作。如使用gzip压缩解压时,使用本地库比使用java时间要缩短大约10%,解压达到50%。在hadoop_home/lib/native

hadoop配置文件core-site.xml可以设置是否使用native

<property>

<name>Hadoop.native.lib

<value>true

</property>

默认是启用本地库,如果频繁使用原生库做压解压任务,可以使用codecpool,通过CodecPoolgetCompressor方法获得Compressor对象,需要传入Codec。这样可以节省创建Codec对象开销 ,允许反复使用。

3.如何选择压缩格式

1).Gzip优点是压缩率高,速度快。Hadoop支持与直接处理文本一样。缺点不支持split当文件压缩在128m内,都可以用gzip
2.)Izo  优点压缩速度快合理的压缩率;支持split,是最流行的压缩格式。支持native库;缺点 比gzip压缩率低,hadoop本身不支持,需要安装;在应用中对lzo格式文件需要处理如 指定inputformatlzo格式
3.)Snappy压缩 高速压缩率合理支持本地库。不支持splithadoop不支持 要安装linux没有对应命令;当MR输出数据较大,作为到reduce数据压缩格式
4.)Bzip2支持split,很高的压缩率,比gzip高,hadoop支持但不支持nativelinux自带命令使用方便。缺点压缩解压速度慢


使用哪压缩具体应用有关,对于巨大,没有储存边界的文件如日志 可以考虑

1.储存不压缩的文件

2.使用支持切分的储存格式 bzip2

3.在应用中切分,然后压缩,需要选择合理数据块的大小,以确定压缩后的块大小
4.使用顺序文件SF,支持压缩和切分
5.使用Avro数据文件,支持压缩切分并增加了编程语言可读写的优势对于大文件,不应该使用不支持切分的压缩格式,否则失去本地性,造成MR应用效率低下。