Hadoop-HDFS学习

Hadoop-HDFS学习

1 摘要

本文介绍了Hadoop体系中最重要的HDFS原理。

2 Hadoop的整体框架

Hadoop由HDFS、MapReduce、HBase、Hive和ZooKeeper等成员组成,其中最基础最重要元素为底层用于存储集群中所有存储节点文件的文件系统HDFS(Hadoop Distributed File System)来执行MapReduce程序的MapReduce引擎。
Hadoop-HDFS学习_第1张图片

  1. Pig是一个基于Hadoop的大规模数据分析平台,Pig为复杂的海量数据并行计算提供了一个简单的操作和编程接口;
  2. Hive是基于Hadoop的一个工具,提供完整的SQL查询,可以将sql语句转换为MapReduce任务进行运行;
  3. ZooKeeper:高效的,可拓展的协调系统,存储和协调关键共享状态;
  4. HBase是一个开源的,基于列存储模型的分布式数据库;
  5. HDFS是一个分布式文件系统,有着高容错性的特点,适合那些超大数据集的应用程序;
  6. MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算。

Hadoop-HDFS学习_第2张图片

3 HDFS架构

Hadoop-HDFS学习_第3张图片

3.1 核心概念介绍

3.1.1 HDFS是什么

HDFS是一个高度容错性的分布式文件系统,可以被广泛的部署于廉价的PC上。它以流式访问模式访问应用程序的数据,这大大提高了整个系统的数据吞吐量,因而非常适合用于具有超大数据集的应用程序中。

HDFS的架构如图所示。HDFS架构采用主从架构(master/slave)。

一个典型的HDFS集群包含一个NameNode节点和多个DataNode节点。NameNode节点负责整个HDFS文件系统中的文件的元数据的保管和管理,集群中通常只有一台机器上运行NameNode实例,DataNode节点保存文件中的数据,集群中的机器分别运行一个DataNode实例。

在HDFS中,NameNode节点被称为名称节点,DataNode节点被称为数据节点。DataNode节点通过心跳机制与NameNode节点进行定时的通信。
Hadoop-HDFS学习_第4张图片

3.1.2 特点

HDFS拥有如下特点:

  1. 流式数据访问,而不是随机读写
  2. 简单一致性模型,一次写入,多次读取
  3. 可用便宜硬件组成高效集群
  4. 高吞吐量
  5. 顺序读写效率很高
  6. 数据追加写入,不能随机读写,不支持更新

3.1.3 不适用HDFS的场景

  1. 低延时的数据访问。因为HDFS设计以吞吐量应用来优化,可能会提高时间延迟为代价。低延时、随机读写多的场景可用HBase。
  2. 大量小文件处理时,并不适用,原因有两点:
    • 大量小文件会占用大量namenode内存;
    • 磁盘寻道时间甚至超过文件读取时间
  3. 不能多个写入线程并发写同一个file
  4. 文件需要修改时不适用,HDFS只支持追加写入

3.2 NameNode

NameNode是分布式文件系统中的管理者,存储文件系统的meta-data,主要负责管理文件系统的namespace(命名空间),集群配置信息,block(存储块)的复制。

3.2.1 NameNode相关概念

3.2.1.1 NameSpace

这里的NameSpace就是指HDFS类似经典的层级文件组织架构,可创建、删除文件,从一个目录移动文件到另一个文件,重命名文件或目录等。

NameSpace由NameNode管理,会记录所有对HDFS文件系统NameSpace的操作到EditsLog。

文件副本数被称为该文件的复制因子,该信息由NameNode保存。

3.2.1.2 Fsimage
  • Fsimage(File System Image),他包括整个HDFS文件系统命名空间(含block到文件的映射和文件系统属性)。
  • Fsimage本身是一个NameNode所在机器操作系统中的文件
  • 即HDFS文件系统命名空间,镜像文件,其实就是元数据快照文件(文件目录树)。存储某一时段NameNode内存元数据信息。
3.2.1.3 EditLog
  • 概念
    • EditLog用于持久化所有对HDFS文件系统元数据的日志文件
    • EditLog本身是一个NameNode所在机器操作系统中的文件
    • 比如,创建一个新的文件时,NameNode也会插入一条数据到EditLog来记录此次操作。
      修改文件的复制因子也会同样插入一条数据到EditLog。
  • 目的
    就算可高效读取FsImage,但将不断增加的操作合并到Fsimage却是十分低效的。所以HDFS中将所有操作持久化到EditLog,当checkpoint发生时,再将这段时间内的EditLog应用到Fsimage。
3.2.1.4 元数据内存
  • NameNode会将整个文件系统命名空间和文件的block映射在内存中维护。
  • DataNode上报块后,块到DataNode的映射也是在NameNode内存中维护。
3.2.1.5 Fstime

保存最近一次checkpoint的时间
注:以上这些文件(Fsimage EditLog Fstime)是保存在linux的文件系统中,而不是HDFS

3.2.1.6 CheckPoint
  • 概念
  1. 当NN启动或是Checkpoint触发时
  2. 会从本地磁盘读取Fsimage和EditLog
  3. 将EditLog中的所有操作事务应用到已读入内存的Fsimage
  4. 结果生成新的Fsimage并写入磁盘
  5. 此时可以truncate旧的EditLog(因为所记录的操作事务已经合并到新的Fsimage)
  • 目的
    通过获取文件系统元数据的快照,并将其保存到FsImage,由此来确保HDFS具有文件系统元数据的一致视图。
  • 触发时机
  1. 根据时间循环出发
  2. 根据HDFS事务增加定时触发
  • 配置
  • dfs.namenode.checkpoint.period 指定两次checkpoint的最大时间间隔,默认3600秒。
  • dfs.namenode.checkpoint.txns文件系统操作事务累积阈值
  • 如果两个都设置了,就以先达到的为触发CheckPoint条件。
  • fs.checkpoint.size 规定edits文件的最大值,一旦超过这个值则强制checkpoint,不管是否到达最大时间间隔。默认大小是64M。

3.2.2 NameNode的职责

  • 维护树状目录结构(NameSpace)
  • 分配并记录每个文件由哪些block组成,以及每个block的信息(大小、时间戳等)
  • 决定block到DataNodes的映射
  • 将HDFS的文件和目录元数据存储在一个叫fsimage的文件中,每次保存fsimage之后到下次保存之间的所有HDFS相关操作,将会记录在editlog文件中
  • 响应客户端的Block位置请求,因为NameNode拥有从DataNode上报的所有Block的位置信息,存放在内存,所以检索非常高效。注意NameNode不响应数据请求,避免成为性能瓶颈。
  • 执行文件系统命名空间相关操作,如打开、关闭、重命名文件和目录
  • 被动接受DataNodeHeartBeat,记录DataNode上报的block信息
  • 通过HeartBeat的回应向DataNode发送命令,本身不做重量级的工作

3.2.3 NameNode 高可用

3.2.3.1 基本概念

NameNode会维护一个fsimage文件,也就是namenode中metedata的镜像,但是fsimage不会随时与namenode内存中的metedata保持一致,而是每隔一段时间通过合并edits文件来更新内容。Standby Namenode主要工作就是合并fsimage和edits文件,以此更新NameNode的metedata。

NameNode上维护一个故障转移控制器进程(FailoverController,比如zkfc),监控着Active NameNode(心跳),并在失效时进行故障切换。

3.2.3.2 Fsimage和Edislog刷新流程

NameNode迁移执行过程:
从NameNode上下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,替换旧的fsimage。
Hadoop-HDFS学习_第5张图片
Fsimage

  1. Standby Namenode通知Active Namenode切换edits文件
  2. Standby Namenode从Active Namenode获得fsimage和Edits Log(通过http)
  3. Standby Namenode将Fsimage载入内存,然后开始合并EditsLog,得到新的Fsimage
  4. Standby Namenode将新的Fsimage发回给Active Namenode
  5. Active Namenode用新的Fsimage替换旧的Fsimage,并删除旧的EditsLog
3.2.3.3 基于 QJM 的 HA 解决方案。

在该方案中主备 NameNode 之间通过一组JournalNode同步元数据信息,一条数据只要成功写入多数的 JournalNode 即认为写入成功。 通常配置奇数个(2N+1)个 JournalNode,这样,只要 N+1 个写入成功就认为数据写入成功,此时最多容忍 N-1 个 JournalNode 挂掉,比如 3 个 JournalNode 时,最多允许 1 个 JournalNode 挂掉,5 个 JournalNode 时,最多允许 2 个 JournalNode 挂掉。

StandBy NameNode观察到EditLog变化,就会读取并更新其内部的Fsimage。 一旦Active NameNode挂掉,StandBy NameNode会保证读取所有EditLog。其实原理和上面通用的方案步骤相同。

基于QJM的HDFS高可用架构如下图所示:
Hadoop-HDFS学习_第6张图片

3.3 DataNode

3.3.1职责

  • 维护数据block:一个block是一个本地文件
  • 处理客户端提交的数据的写入、读取请求
  • 执行由NameNode给的指令,如block的创建、复制、删除等
  • 可以配置多个磁盘
  • 允许部分磁盘失败
  • 根据剩余空间比例选择新block的存放位置
  • 定期以心跳方式向NameNode上报Blockreport,包含该DataNode的所有block列表

3.3.2 Block文件块

  • Block是HDFS中最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。HDFS默认Block大小是128MB,比如一个256MB文件,共有256/128=2个Block。但不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间。
  • Block设计的比磁盘块大的原因是,使得文件传输时间/(文件传输+寻道时间) 比例尽可能提高。但也不能太大,否则会减少mapreduce的任务数,导致处理变慢。
  • DataNode将每个HDFS数据block存储在其本地文件系统中的单独文件中,但并不会在同一目录中创建所有文件,而是采用算法来确定每个目录的最佳文件数,并适当地创建子目录(在同一目录中创建所有本地文件并不是最佳选择,因为本地文件系统可能无法有效地支持单个目录中的大量文件)。
  • 当DataNode启动时,它会扫描其本地文件系统,生成与每个本地文件对应的所有HDFS数据块的列表,并将此报告发送到NameNode。 该报告称为Blockreport。
  • DataNode并不了解HDFS文件本身。

3.3.3 文件

  • HDFS文件由若干block组成。
  • HDFS文件只能追加写,不能修改
  • HDFS文件写入不能并发,只能有一个写入者

3.3.4 Replication-副本

hdfs文件块的副本,默认是三个。所以一般存hdfs文件的硬盘不用做RAID。

文件副本分别存在以下位置:
Hadoop-HDFS学习_第7张图片

  • a:跟写数据的客户端同节点(如果客户端运行在集群之外,就随机选择一个节点,不过会避免选存储空间少或负载高的节点)
  • b:和a节点同机柜不同机架的节点
  • c:和b节点同机架但不同机器的节点
  • 如果有更多副本,那就随机选择,原则是尽量在一个机架上少放副本。

HDFS 运行在跨越大量机架的集群之上。两个不同机架上的节点是通过交换机实现通信的,在大多数情况下,相同机架上机器间的网络带宽优于在不同机架上的机器。

在开始的时候,每一个数据节点自检它所属的机架 id,然后在向名字节点注册的时候告知它的机架 id。HDFS 提供接口以便很容易地挂载检测机架标示的模块。一个简单但不是最优的方式就是将副本放置在不同的机架上,这就防止了机架故障时数据的丢失,并且在读数据的时候可以充分利用不同机架的带宽。这个方式均匀地将复制分散在集群中,这就简单地实现了组建故障时的负载均衡。然而这种方式增加了写的成本,因为写的时候需要跨越多个机架传输文件块。

下面展示了NameNode拥有的两个文件的副本元数据,及在多个DataNode上的分布情况:

  • part-0
    2个副本,block id为{1,3}
  • part-1
    3个副本,block id为{2,4,5}
    Hadoop-HDFS学习_第8张图片

3.3.5 Federal HDFS

因为Namenode保存所有文件有内存扩展限制,所以在超大集群扩展时会成为瓶颈。2.x引入Federal HDFS概念,允许启动多个NameNode来进行扩展,每个NameNode管理文件系统命名空间的一部分。例如,NameNode1管理/user目录下的所有文件,NameNode2管理/share目录下的所有文件。

每个NameNode会维护一个NameSpace Volume(命名空间卷),包括了命名空间的源数据,以及有一个容纳该Namespace下的文件的所有Block的Block池。也就是说,每个NameNode之间相互独立不影响。所以,DataNode需要注册到所有NameNode,并且存放来自多个Block池的Block。

4 数据流

4.1 Block Packet和Chunk

在进行数据读写的流程分析前,我们先讲三个基本概念:

  • block
    这个大家应该知道,文件上传前需要分块,这个块就是block,一般为128MB,当然你可以去改(不推荐)。如果设置的块太小:寻址时间占比过高。块太大:Map任务数太少,作业执行速度变慢。block是这三个概念中最大的一个单位。
  • packet
    packet是第二大的单位,它是client端向DataNode,或DataNode的PipLine之间传数据的基本单位,默认64KB。
  • chunk
    chunk是最小的单位,它是client向DataNode,或DataNode的Pipeline之间进行数据校验的基本单位,默认512Byte,因为用作校验,故每个chunk需要带有4Byte的校验位。所以实际每个chunk写入packet的大小为516Byte。由此可见真实数据与校验值数据的比值约为128 : 1。(即64*1024 / 512)

例如,在client端向DataNode传数据的时候,HDFSOutputStream会有一个chunk buffer,写满一个chunk后,会计算校验和并写入当前的chunk,之后再把带有校验和的chunk写入packet。

当一个packet写满后,packet会进入DataQueue队列,其他的DataNode就是从这个DataQueue获取client端上传的数据并存储的。同时一个DataNode成功存储一个packet之后会返回一个ack packet,放入ack Queue中。

4.2 文件写入

4.2.1 写入流程简述:

  1. Client向NameNode发起文件写入的请求
  2. NameNode根据文件大小和文件块配置情况,返回给Client它所管理部分DataNode的信息。
  3. Client将文件划分为多个文件块,根据DataNode的地址信息,按顺序写入到每一个DataNode块中。

4.2.2 写入详细流程

Hadoop-HDFS学习_第9张图片

  1. HDFS Client中调用DistributedFileSystem对象Create方法新建文件
  2. 通过对NameNode RPC调用,在FileSystem NameSpace中新建一个文件,注意此时文件尚无数据块。NameNode会进行文件存在和用户权限的检查:
    • 检查通过就会创建一个文件记录,将此次写操作写入EditLog,并返回一个FSDataOutputStream对象
    • 检查不通过就抛出异常给Client
  3. Client拿到FSDataOutputStream,他内部封装了DFSOutputStream,负责处理和DataNode、NameNode通信。此时可以开始写数据。在写数据时,DFSOutputStream将数据切分为一个个packet(数据包),并写入内部DataQueue(数据队列)。
  4. DataStreamer消费上述 DataQueue,并提供挑选出的DataNode列表来要求NameNode分配适合的新Block来存储数据副本。这一组DataNode会形成pipeline管道。当DataStreamer把数据流式传输到管道中的第一个DataNode后,该DataNode会先存放数据包(packet),然后转发给流水线中的第二个DataNode。第二个DataNode收到后同样转发给第三个DataNode。注意这里是流的形式在管道传输,而不是一个block或一个文件,所以效率很高。
  5. DFSOutputStream 中也维护了一个内部队列ackQueue用来存放那些在DataNode写数据成功后发回的 ack。只有当所有管道中的DataNode都发回了 ack 后,才会将该packet从管道中移除。
  6. Client完成数据写入,调用FSDataOutputStream的close方法关闭流
  7. 第六步操作会flush所有剩余的数据包到DataNode 管道中,然后联系NameNode来标记文件已经写入完成,并等待发回的ack

4.2.3 异常处理

4.2.3.1 写入block时单个DataNode故障

关闭pipeline,将ackQueue中的所有packet 放到 DataQueue的前段,这样管道中失败DataNode节点下游的DataNode不会丢失任何packet。当前写入的Block(位于正确的DataNode的上的副本)会被给与新的标识然后传递给NameNode。这样做的目的是在失败的DataNode恢复后删掉这个不完整的Block(因为写入失败了)。

在出错DataNode从管道中删除后,会在两个工况良好的DataNode间建立新的pipeline。随后将该block的剩余的数据写入管道中正常的DataNode。

最后,NameNode将在新的其他DataNode上创建该block的副本。接下来,其他block就按正常流程处理即可。

4.2.3.2 写入block时多个DataNode故障

这样情况很少发生。只要写入的副本数达到了dfs.namenode.replication.min(默认为1)就会成功,然后会按dfs.replication(默认为3)异步复制该block到其他节点上。

4.2.4 写入时NameNode选择DataNode的原则

Hadoop-HDFS学习_第10张图片

  1. 跟客户端同节点(如果客户端运行在集群之外,就随机选择一个节点,不过会避免选存储空间少或负载高的节点)
  2. 和a节点同机柜不同机架的节点
  3. 和b节点同机架但不同机器的节点

如果有更多副本,那就随机选择,原则是尽量在一个机架上少放分本

4.2.5 HDFS副本策略好处

  1. 是实现了数据负载均衡
  2. 写入时只遍历一个交换机,充分利用带宽
  3. 读取时可从机架中选择读取
  4. 块可在集群均匀分布

4.3 文件读取:

4.3.1 读取流程简述

  1. Client向NameNode发起文件读取的请求
  2. NameNode返回文件存储的DataNode的信息。
  3. Client读取文件信息。

4.3.2 读取流程详述

Hadoop-HDFS学习_第11张图片

  1. Client调用FileSystem对象(DistributedFileSystem的一个实例)的open方法打开目标文件。建立一个FSDataOutputStream
  2. DistributedFileSystem 以RPC调用方式访问NameNode,获得目标文件的若干起始块的位置。NameNode只会响应文件块请求而不是数据请求,这些信息存放在NameNode内存中所以速度很快。此时会根据DataNode和Client的拓扑距离来排序,优先选本地。DistributedFileSystem 返回一个FSDataInputStream对象给Client,该对象封装了DFSInputStream对象管理DataNode、 NameNode的IO
  3. Client对FSDataInputStream输入流调用read方法
  4. FSDataInputStream中的DFSInputStream利用刚刚得到的已排序DataNode地址列表连接最近的一个DataNode,将数据传回Client
  5. 读到Block末端时,DFSInputStream关闭与该DataNode连接,并寻找下一个block所在最近的DataNode。客户端读取数据时,block是按照打开DFSInputStream与DataNode新建连接的顺序读取的。他同样会询问NameNode下一批block所在DataNode地址。整个读取过程对Client透明。
  6. Client完成读取后,对FSDataInputStream调用close方法关闭流

4.3.3 异常处理

  1. 读数据故障
    DFSInputStream与DataNode通信遇到错误时,会尝试从读的块次近的DataNode读取数据。并且记下故障DataNode避免以后再从这里读数据。
  2. 数据完整性校验
    DFSInputStream会通过校验和来确认从DataNode来的数据是否完整。如果有损坏,就会尝试从其他DataNode读取Block副本,然后将损坏的Block通知NameNode

4.3.4 HDFS节点拓扑

HDFS不能自己定义网络拓扑结构,必须手动配置。顺序关系如下:

同节点->同机架上的不同节点->同数据中心不同机架->不同数据中心

5 数据一致性模型

5.1 概念

HDFS为了均衡性能设计了一套数据一致性模型。

HDFS写入的数据不能保证立即可见(如果是写入的新建的文件,文件可见数据不可见)。也就是说即使已经做了flush操作该文件长度也有可能为0。

具体来说,数据流必须当数据超过一个Block后,这第一个和之后的Block才对新的reader可见。总之,正在写入的Block对其他reader不可见,除非已经写完该Block。

5.2 hflush

HDFS提供了FSDataOutputStream.hflush方法来使得数据对reader可见。注意,hflush不能保证数据被DataNode写入磁盘而只能保证到内存,也就是说如果机器断电等故障可能导致数据丢失。

5.3 hsync

还有一个hsync方法,和hflush很像,不同之处是hsync除了保证数据对reader可见还会强制持久化数据。hsync有一定性能开销,要适当选择hsync时机。

5.4 close

close方法关闭文件流,并且在此之前会执行hflush。

6 小文件

6.1 小文件带来的问题

HDFS中如果存在大量小文件会占用大量NameNode内存,十分低效。但必须注意,比如1MB的小文件用128MB的Block存储,也只会实际占用1MB磁盘。

6.2 HAR

6.2.1 概念

Hadoop存档文件或HAR文件,高效的文件存档工具,将文件存入HDFS Block,减少NameNode内存使用,对文件访问透明,甚至可以直接作为MapReduce的输入。HAR是通过Archive工具来创建,需要运行MR程序来并行处理输入文件。HAR主要由索引文件和数据文件组成。

6.2.2 不足

建立HAR开销、不可修改、作为MR输入时低效

7 数据完整性

读写过程,数据完整性如何保持?

HDFS会对写入的所有数据计算校验和,并在读取时验证校验和(io.bytes.per.checksum)。一般使用CRC-32校验,占用4个字节。

7.1 校验综述

具体来说,HDFS做法主要是通过校验和验证数据完整性。因为每个chunk中都有一个校验位,一个个chunk构成packet,一个个packet最终形成block,故可在block上求校验和。

HDFS 的client端即实现了对 HDFS 文件内容的校验和 (checksum) 检查:

  1. 客户端创建一个新的HDFS文件
  2. 将新文件分块,然后计算每一个block的校验和,以一个隐藏文件形式保存在同一个 HDFS 命名空间下
  3. 当client端从HDFS中读取文件内容后,它会检查读取到的文件block中的校验和、隐藏文件里block的校验和和是否匹配
  4. 如果不匹配,客户端可以选择从其他 Datanode 获取该数据块的副本

HDFS中文件块目录结构具体格式如下:
${dfs.datanode.data.dir}/
├── current
│ ├── BP-526805057-127.0.0.1-1411980876842
│ │ └── current
│ │ ├── VERSION
│ │ ├── finalized
│ │ │ ├── blk_1073741825
│ │ │ ├── blk_1073741825_1001.meta
│ │ │ ├── blk_1073741826
│ │ │ └── blk_1073741826_1002.meta
│ │ └── rbw
│ └── VERSION
└── in_use.lock
in_use.lock表示DataNode正在对文件夹进行操作
rbw是“replica being written”的意思,该目录用于存储用户当前正在写入的数据。
Block元数据文件(*.meta)由一个包含版本、类型信息的头文件和一系列校验值组成。校验和也正是存在其中。

7.2写入校验

Client写入数据时,会带上数据的校验和。在写入数据的管道上的最后一个DataNode负责校验数据,如果出错会抛异常,由Client决定下一步操作。

7.3 读取校验

Clietn读取数据时会利用从DataNode读取到的校验和(隐藏文件内)和读到的数据进行校验比对,如果校验成功会通知DataNode,DataNode更新日志,可帮助检测磁盘损坏。

7.4 DataNode自检

DataNode上运行着DataBlockScanner,定期自检其上的数据。

7.5 校验失败处理

  1. Client读取数据发现校验失败,将Block和DataNode信息通知NameNode
  2. 抛出ChecksumException
  3. NameNode将这个Block标记为损坏
  4. NameNode以后会将对此Block的请求引流到其他DataNode
  5. NameNode在其他DataNode创建这个Block的副本,保证副本数。
  6. 删除损坏的副本

8 数据压缩

数据文件压缩可以减少磁盘空间开销,加速数据在网络和磁盘上传输速度。
Hadoop-HDFS学习_第12张图片

8.1压缩格式

压缩算法需要权衡空间和时间,压缩速度快的代价往往是压缩比低。

压缩格式 工具 算法 扩展名 是否可切分
Gzip gzip DEFLATE .gz
bzip2 bzip2 bzip2 .bz2
LZ4 LZ4 .lz4
LZO lzop LZO .lzo 是(取决于使用的库)

注:是否可切分指的是搜索数据流的任意位置并进一步往下读取数据,可切分更适合MapReduce。

总的来说,LZO,Snappy压缩速度更快,比gzip快一个数量级,但压缩比较低。Snappy解压速度比LZO高出很多。

8.2 压缩切分与MapReduce

Hadoop应用处理的数据集非常大,因此需要借助于压缩,使用哪种压缩格式与待处理的文件的大小格式和所使用的工具相关。

对于gzip,MR不会直接尝试切分.gzip格式文件,而是要读取这个文件的所有块,然后用一个map任务处理所有这些块。但这会牺牲数据本地性,因为大多数文件快没有存储在该map任务的节点。

LZO可以在预处理的时候使用Hadoop LZO库中的索引工具,来构建切分点索引。

下面按照效率从高到低排列:

  1. 使用容器文件格式,例如SequenceFile、 Rcfile或者Avro,这些文件格式同时支持压缩和切分,通常最好与一个快速压缩缩工具联合使用,例如LZQ,LZ4,或者 Snappy
  2. 直接使用支持切分的压缩格式,例如bzip2(尽管bzip2非常慢),或者使用通过索引实现切分的压缩格式,例LZO
  3. 在应用中将文件切分成块,并使用任意一种压缩格式为每个数据块建立压缩文件(不论它是否支持切分)。这种情况下,需要合理选择Block的大小,以保证压缩后数据块的大小近似于Block的太小
  4. 存储未经压缩的文件
    对大文件来说,不要使用不支持切分整个文件的压缩格式,因为会失去数据的本地特性,进而造成 MapReduce应用效率低下

9 序列化

因为HDFS中各个节点通信用的RPC协议,会将消息序列化成二进制流发送,到达目的地后再将二进制流反序列化为原始消息。

RPC序列化格式的四大理想属性是:格式紧凑、序列化反序列化速度快、格式可扩展、支持不同语言读写。

9.1 Writable

Hadoop使用的是自己的序列化格式Writable,它符合紧凑、速度快,但扩展性不好。

9.2 Avro

解决了Writable多语言支持不足的问题。

10 文件数据结构

考虑到某些分布式场景中大对象存在单个文件中不能实现扩展,所以在HDFS有一些高层次容器。

10.1 SequenceFile

10.1.1 简介

  • SequenceFile面向行

SequenceFile是一个二进制key/value键值对持久数据结构,可以自己选择key(比如LongWritable类型所表示的时间戳),值可以使Writable类型(表示日志记录的数量)。

SequenceFile也可以作为小文件的容器,以获得更高效的存储和处理。

SequenceFile.writer写入时会在顺序写文件过程中插入特殊字符来分隔若干记录,称为同步标识。注意该同步标识体积小,且始终处于每条记录的边界处即不会出现在记录内部。所以可以将SequenceFile作为MR输入,因为该文件可使用SequenceFileInputFormat读取并切分map处理。

以星号代替同步标识的一个SequenceFile部分内容如下:
Hadoop-HDFS学习_第13张图片

10.1.2 格式

SequenceFile包括文件头(代码、版本号、key/value名称,数据压缩、用户定义元数据、随机生成的该文件的同步标识(Sync))和若干Record。

Record的Value默认未开启压缩,可按单条(Key无压缩)或Block压缩(多条Record)。未开启压缩和单Record压缩如图:
Hadoop-HDFS学习_第14张图片
开启Block压缩如图:
Hadoop-HDFS学习_第15张图片

10.1.3 查看

可以使用如下命令查看HDFS中的SequenceFile:

hadoop fs -text number.seq | head

10.2 MapFile

  • MapFile面向行
  • MapFile是已经排序过的SequenceFile**,有索引(默认隔128个key就放到索引,也是个SequenceFile),可以按key查找。
  • 主数据文件是另一个SequenceFile,包含所有map对,且按key排序
  • 使用MapFile.Writer进行写操作时必须按key顺序append,否则报错
  • 可以视为java.util,map的持久化形式。
  • 还有一些MapFile变种:
    • SetFile
      存有序的Writable Key集合
    • ArrayFile
      Key为整型表示数组元素索引,Value为Writable
    • BloomMapFile
      利用快速的布隆过滤器原理探测,通过后才会调用其get方法获取Value。

10.3 Avro

  • Avro面向行
  • Avro文件紧凑且可切分,面向大规模数据处理,且能跨语言使用 (因为内部对象使用schema而不是Java方法描述)。

10.4 RCFile

  • RCFile面向列
  • Record Columnar File
  • 已经被Hive的ORCFile和Parquet取代
  • 格式如下
    Hadoop-HDFS学习_第16张图片
    面向列的格式中,文件中的行或Hive中的一张表被分割成若干row split,每个Split面向列存储。

10.5 ORCFile

  • ORCFile面向列
  • Optimized Record Columnar File

10.6 Parquet

  • Parquet面向列

11通讯协议

  • 所有HDFS通信协议都在TCP / IP协议之上构建。
  • 客户端使用ClientProtocol与NameNode机器配置的TCP端口的建立连接。
  • DataNode使用DataNode协议与NameNode通信。
  • HDFS RPC抽象包装了ClientProtocol和DataNodeProtocol。
  • 按照设计,NameNode永远不会启动任何RPC,只会响应DataNodes或客户端发出的RPC请求。

12 系统健壮性

12.1 DataNode失联

所有DataNode都会周期性地向NameNode发送心跳,当网络异常即发送网络分区时,会导致部分DataNode无法连接到NameNode。此时NameNode会侦测到最近无心跳的DataNode(阈值默认为10分钟),并标记为死亡节点,不再转发新的客户端IO请求给他们,其上的数据也不再可用。

DataNode死亡还会使得某些Block的副本数少于指定数量,NameNode会一直追踪那些需要被复制的block,而且一旦需要(比如DataNode失联或硬盘损坏、副本崩溃、文件副本因子调大等)就会立刻构建、初始化Block副本。

12.2 集群Rebalance

当某个DataNode上的空闲磁盘空间下降到阈值时,某些主题的数据移动到其他DataNode。

12.3 数据完整性-checksum校验和

可能会发生获取一个Block数据中途发生崩溃,原因如存储设备故障、网络故障、软件Bug等。

HDFS客户端实现了校验和来检查HDFS文件内容。创建HDFS文件时,同时会为该文件的每个Block计算校验和并将这些校验和存在单独的一个隐藏文件中(同一个namespace)。

当客户端读取文件内容时,会先通过关联的校验和文件来对接收到的文件进行校验匹配检查。当校验不通过时,客户端可以重选其他DataNode来获取该文件Block副本。

12.4 元数据磁盘故障

FsImage和EditLog如果挂了,可导致HDFS服务失效。可对NameNode设置,持有多个这两个文件的副本,同步更新。

也可以采用NFS共享存储或是JounalNode(推荐)对NameNode做HA处理。

或是用zkfc(ZKFailoverController)来检测NameNode在ZK中的状态,异常时切换为StandBy Namenode。

12.5 Snapshots快照

Snapshots支持在特定时刻存储数据副本。 快照功能的一种用途可以是将损坏的HDFS实例回滚到先前已知的工作良好的某个时间点。

13 HDFS的内存存储

Hadoop2.6.0提供了堆外内存持久化的能力,如果在数据刷入磁盘前重启服务,可能丢失数据。
Hadoop-HDFS学习_第17张图片

可参见Memory Storage Support in HDFS

14 Archive Storage

Archival Storage可将不断增长的存储容量与计算容量分离。可用那些更高密度和低成本的存储能力及较低的计算能力的节点可用于存储冷数据。

可参见Archival Storage, SSD & Memory

15 HDFS常用命令

15.1 dfs

  • 分页查看文件内容
    hdfs dfs -text /xxx/20190813/abc |more
  • 查看目录下文件
    hdfs dfs -ls -h /xxx/20190813

15.2 fsck

  • 检查文件详细信息
    hdfs fsck /xxx/20190813/abc.lzo -locations -blocks -files
  • 查看openforwrite的文件
    hdfs fsck /xxx/20190813 -openforwrite | grep OPENFORWRITE |awk -F ' ' '{print $1}'

15.3 debug

  • 强制hsync并close hdfs file
    hdfs debug recoverLease -path /xxx/20190813/abc.lzo

0xFF 参考文档

HDFS 副本放置策略的研究和优化
Hadoop学习笔记—1.基本介绍与环境配置

《Hadoop权威指南第四版》

你可能感兴趣的:(HDFS,hadoop)