HDFS的IO操作

一、数据完整性

  IO操作过程中难免会出现数据丢失或脏数据,数据传输得量越大出错得几率越高,而用户希望储存和处理数据的时候,不会有任何损失或者损坏。
  Hadoop提供两种校验
1校验和(常用循环冗余校验CRC-32)
2运行后台进程来检测数据块

校验和
a.写入数据节点验证。
  Hdfs会对写入的所有数据计算校验和,并在读取数据时验证校验和。
  元数据节点负责在验证收到的数据后,储存数据及其校验和。在收到客户端数据或复制其他datanode的数据时执行。
  正在写数据的客户端将数据及其校验和发送到一系列数据节点组成的管线,管线的最后一个数据节点负责验证校验和
b.读取数据节点验证
  客户端读取数据节点数据也会验证校验和,将它们与数据节点中储存的校验和进行比较。
  每个数据节点都持久化一个用于验证的校验和日志。
  客户端成功验证一个数据块后,会告诉这个数据节点,数据节点由此更新日志。
c.恢复数据
  由于hdfs储存着每个数据块的备份,它可以通过复制完好的数据备份来修复损坏的数据块来恢复数据。
d.Localfilesystem类
  Hadoop的LocalFileSystem类是用来执行客户端的校验和验证。当写入一个名为filename的文件时文件系统客户端会在包含文件块校验和的同一目录内建立一个名为Filename.crc的隐藏文件。
e.ChecksumfileSystem类
  LocalFileSystem类通过ChecksumFileSystem类来完成自己的任务
FileSystem rawFs;
  FileSystem checksummedFs=new ChecksumFileSystem(rawFS);
  可以通过CheckFileSystem的getRawFileSystem()方法获取源文件系统。
  当检测到错误,CheckFileSystem类会调用reportCheckSumFailure()方法报告错误,然后LocalFileSystem将这个出错的文件和校验和移到名为bad_files的文件夹内,管理员可以定期检查这个文件夹。

运行后台进程来检测数据块
  数据节点后台有一个进程DataBlockScanner,定期验证储存在这个数据节点上的所有数据项,该项措施是为解决物理储存媒介上的损坏。DataBlockScanner是作为数据节点的一个后台线程工作的,跟着数据节点同时启动
  它的工作流程如图

  由于对数据节点上的每一个数据块扫描一遍要消耗较多系统资源,因此扫描周期的值一般比较大,
  这就带来另一个问题,就是在一个扫描周期内可能出现数据节点重启的情况,所以为了提高系统性能,避免数据节点在启动后对还没有过期的数据块又扫描一遍,
  DataBlockScanner在其内部使用了日志记录器来持久化保存每一个数据块上一次扫描的时间
  这样的话,数据节点可以在启动之后通过日志文件来恢复之前所有的数据块的有效时间。

二.文件的格式

  HDFS和MR主要针对大数据文件来设计,在小文件处理上效率低.解决方法是选择一个容器,将这些小文件包装起来,将整个文件作为一条记录,可以获取更高效率的储存和处理,避免多次打开关闭流耗费计算资源.hdfs提供了两种类型的容器 SequenceFile和MapFile。
小文件问题解决方案
  在原有HDFS基础上添加一个小文件处理模块,具体操作流程如下:
  a.当用户上传文件时,判断该文件是否属于小文件,如果是,则交给小文件处理模块处理,否则,交给通用文件处理模块处理。在小文件模块中开启一定时任务,其主要功能是当模块中文件总size大于HDFS上block大小的文件时,则通过SequenceFile组件以文件名做key,相应的文件内容为value将这些小文件一次性写入hdfs模块。
  b.同时删除已处理的文件,并将结果写入数据库。
  c.当用户进行读取操作时,可根据数据库中的结果标志来读取文件。
SequenceFile
  Sequence file由一系列的二进制key/value组成,如果key为小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。Hadoop-0.21.0版本开始中提供了SequenceFile,包括Writer,Reader和SequenceFileSorter类进行写,读和排序操作。该方案对于小文件的存取都比较自由,不限制用户和文件的多少,支持Append追加写入,支持三级文档压缩(不压缩、文件级、块级别)。其存储结构如下图所示:

SequenceFile储存
  文件中每条记录是可序列化,可持久化的键值对,提供相应的读写器和排序器,写操作根据压缩的类型分为3种
1.Write 无压缩写数据
2.RecordCompressWriter记录级压缩文件,只压缩值
3.BlockCompressWrite块级压缩文件,键值采用独立压缩方式
  在储存结构上,sequenceFile主要由一个Header后跟多条Record组成,如图

  前三个字节是一个Bytes SEQ代表着版本号,同时header也包括key的名称,value class , 压缩细节,metadata,以及Sync markers。Sync markers的作用在于可以读取任意位置的数据。
  在recourds中,又分为是否压缩格式。当没有被压缩时,key与value使用Serialization序列化写入SequenceFile。当选择压缩格式时,record的压缩格式与没有压缩其实不尽相同,除了value的bytes被压缩,key是不被压缩的。

  当保存的记录很多时候,可以把一串记录组织到一起同一压缩成一块。
  在Block中,它使所有的信息进行压缩,压缩的最小大小由配置文件中,io.seqfile.compress.blocksize配置项决定。
SequenceFile写操作
  通过createWrite创建SequenceFile对象,返回Write实例,指定待写入的数据流如FSDataOutputStream或FileSystem对象和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流。也就是在执行文件写操作的时候,该文件是不可读取的

  排序后的SequeneceFile,并且它会额外生成一个索引文件提供按键的查找.读写mapFile与读写SequenceFile
  非常类似,只需要换成MapFile.Reader和MapFile.Writer就可以了。
  在命令行显示mapFile的文件内容同样要用 -text

  SequenceFile文件是用来存储key-value数据的,但它并不保证这些存储的key-value是有序的,
  而MapFile文件则可以看做是存储有序key-value的SequenceFile文件。
  MapFile文件保证key-value的有序(基于key)是通过每一次写入key-value时的检查机制,这种检查机制其实很简单,就是保证当前正要写入的key-value与上一个刚写入的key-value符合设定的顺序,
  但是,这种有序是由用户来保证的,一旦写入的key-value不符合key的非递减顺序,则会直接报错而不是自动的去对输入的key-value排序
  mapFile既然是排序和索引后的SequenceFile那么自然可以把SequenceFile转换为MapFile使用mapFile.fix()方法把一个SequenceFile文件转换成MapFile

三、压缩

  Hadoop 作为一个较通用的海量数据处理平台,每次运算都会需要处理大量数据,我们会在 hadoop 系统中对数据进行压缩处理来优化磁盘使用率,提高数据在磁盘和网络中的传输速度,从而提高系统处理数据的效率。在使用压缩方式方面,主要考虑压缩速度和压缩文件的可分割性。综合所述,使用压缩的优点如下:
1. 节省数据占用的磁盘空间;
2. 加快数据在磁盘和网络中的传输速度,从而提高系统的处理速度。
  Hadoop 对于压缩格式的是自动识别。如果我们压缩的文件有相应压缩格式的扩展名(比如 lzo,gz,bzip2 等)。Hadoop 会根据压缩格式的扩展名自动选择相对应的解码器来解压数据,此过程完全是 Hadoop 自动处理,我们只需要确保输入的压缩文件有扩展名。
  Hadoop 对每个压缩格式的支持, 详细见下表:
压缩格式  工具  算法  扩展名  多文件  可分割性
DEFLATE  无  DEFLATE  .deflate 不     不
GZIP    gzip DEFLATE  .gzp  不     不
ZIP     zip EFLATE   .zip   是    是,在文件范围内
BZIP2   bzip2 BZIP2   .bz2   不    是
LZO    lzop  LZO  .lzo    不    是
性能对比
Hadoop 下各种压缩算法的压缩比,压缩时间,解压时间见下表:
表 2. 性能对比
压缩算法  原始文件大小  压缩文件大小  压缩速度  解压速度
gzip     8.3GB      1.8GB       17.5MB/s   58MB/s
bzip2     8.3GB      1.1GB     2.4MB/s     9.5MB/s
LZO-bset   8.3GB      2GB       4MB/s     60.6MB/s
LZO     8.3GB      2.9GB       49.3MB/s   74.6MB/s
因此我们可以得出:
1) Bzip2 支持split,很高的压缩率,比gzip高,hadoop支持但不支持native,linux自带命令使用方便。缺点压缩解压速度慢。Bzip2支持切分 splitting.hdfs上文件1GB,如按照默认块64MB,那么这个文件被分为16个块。如果把这个块放入MR任务 ,将有16个map任务输入。如果算法不支持切分,后果是MR把这个文件作为一个Map输入。这样任务减少了,降低了数据的本地性。
2) Gzip 优点是压缩率高,速度快。Hadoop支持与直接处理文本一样。缺点不支持split,当文件压缩在128m内,都可以用gzip
3) Izo 优点压缩速度快 合理的压缩率;支持split,是最流行的压缩格式。支持native库;缺点 比gzip压缩率低,hadoop本身不支持,需要安装;在应用中对lzo格式文件需要处理如 指定inputformat为lzo格式

使用哪种压缩和具体应用有关,对于巨大,没有储存边界的文件如日志 可以考虑
1.储存不压缩的文件
2.使用支持切分的储存格式 bzip2
3.在应用中切分,然后压缩,需要选择合理数据块的大小,以确定压缩后的块大小
4.使用顺序文件SF,支持压缩和切分
5.使用Avro数据文件,支持压缩切分并增加了编程语言可读写的优势对于大文件,不应该使用不支持切分的压缩格式,否则失去本地性,造成MR应用效率低下。
  这里提一下,文件的可分割性在 Hadoop 中是很非常重要的,它会影响到在执行作业时 Map 启动的个数,从而会影响到作业的执行效率。
  所有的压缩算法都显示出一种时间空间的权衡,更快的压缩和解压速度通常会耗费更多的空间。在选择使用哪种压缩格式时,我们应该根据自身的业务需求来选择。
CodeC
  实现了一种压缩解压算法。Hadoop中压缩解压类实现CompressionCodec接口
  createOutputStream来创建一个CompressionOutputStream,将其压缩格式写入底层的流
  演示HDFS上一个1.bzip2算法压缩的文件解压,然后把解压的文件压缩成2.gz

本地库
  Hadoop使用java开发,但是有些需求和操作并不适合java,所以引入了本地库 native。可以高效执行某些操作。如使用gzip压缩解压时,使用本地库比使用java时间要缩短大约10%,解压达到50%。在hadoop_home/lib/native下,在hadoop配置文件core-site.xml可以设置是否使用native
  默认是启用本地库,如果频繁使用原生库做压解压任务,可以使用codecpool,通过CodecPool的getCompressor方法获得Compressor对象,需要传入Codec 。这样可以节省创建Codec对象开销 ,允许反复使用。

四、序列化

什么是序列化?
  将结构化对象转换成字节流以便于进行网络传输或写入持久存储的过程。
什么是反序列化?
  将字节流转换为一系列结构化对象的过程。
序列化用途:
1、作为一种持久化格式。
2、作为一种通信的数据格式。
3、作为一种数据拷贝、克隆机制。
为什么Hadoop基本类型还要定义序列化?
1.Hadoop在集群之间通信或者RPC调用时需要序列化,而且要求序列化要快,且体积要小,占用带宽小。
2.java的序列化机制占用大量计算开销,且序列化结果体积过大;它的引用机制也导致大文件不能被切分,浪费空间;此外,很难对其他语言进行扩展使用;
3.java的反序列化过程每次都会构造新的对象,不能复用对象。

五、Hadoop Writable基本类型

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类。
  unicode编码是一个很大的集合,可以容纳100多万个符号。具体的符号对应表可以查询unicode.org 它只规定了符号的二进制代码,没有规定如何存储,而utf-8就是unicode的实现还有utf16等。对于单个字符字节第一位为0,后面7位为这个符号的unicode码。因此对于英语字母,utf-8编码和ASCII码是相同的。所有\u0001~\u007f会以单字节储存。\u0080~\u07ff的unicode会以双字节储存,\u0800~\uFFFF的会以3字节存储。
NullWritable
  是writable类型的特殊类型,序列化长度为0,它充当占位符但不真在数据流中读写。NullWritable是单实例类型,通过NullWriable.get()方法获取
BytesWritable
  相当于二进制数据数组的包装。以字节数组{1,2,3,4}它的序列化格式是4字节表示字节数 ,每2个字节表示一个数据即 “0000 0004 0102 0304” 和Text一样BytesWritable也是可变的 ,可以通过set来修改
ObjectWritable和GenericWritable
  ObjectWritable是对java基本类型的和这些类型的数组类型的通用封装 ,使用RPC来封送
来源:东软睿道

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值