Hadoop-HDFS 基础回顾

一.block

    HDFS 作为一种文件系统,当然也需要有‘block’的概念。不过HDFS的block一般比较大,默认为128MB。与普通的管理单个磁盘的文件系统一样,HDFS也将文件分割成block,每个block都作为一个独立的单元分别保存。不同点在于,在HDFS中,小于block的文件不会占用一个block的空间。(比如,文件大小为1MB,那么它会占用一个HDFS的block,但是只使用底层磁盘1MB的空间,而不是128MB。)
     block为什么设置成128M:

          如果块设置过大

  • 从磁盘传输数据的时间会明显大于寻址时间,导致程序在处理这块数据时,变得非常慢;

  • mapreduce中的map任务通常一次只处理一个块中的数据,如果块过大运行速度也会很慢。

         如果块设置过小

  • 存放大量小文件会占用NameNode中大量内存来存储元数据,而NameNode的内存是有限的,不可取;

  • 文件块过小,寻址时间增大,导致程序一直在找block的开始位置。

因而,块适当设置大一些,减少寻址时间,传输一个由多个块组成的文件的时间主要取决于磁盘的传输速率。

        为什么默认是128M

  • HDFS中平均寻址时间大概为10ms;

  • 经过前人的大量测试发现,寻址时间为传输时间的1%时,为最佳状态;
    所以最佳传输时间为10ms/0.01=1000ms=1s

  • 目前磁盘的传输速率普遍为100MB/s;
    计算出最佳block大小:100MB/s x 1s = 100MB
    所以我们设定block大小为128MB。

实际在工业生产中, 磁盘传输速率为200MB/s时,一般设定block大小为256MB 磁盘传输速率为400MB/s时,一般设定block大小为512MB

 

二.HDFS 架构体系

       HDFS 采用Master/Slave的架构来存储数据,这种架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode。一个HDFS集群是由一个NameNode和一定数目的DataNode组成的。NameNode是一个中心服务器,负责管理文件系统的名字空间 (Namespace )及客户端对文件的访问。集群中的DataNode一般是一个节点运行一个DataNode进程,负责管理它所在节点上的存储。

  • NameNode的工作: 一个HDFS集群包含一个NameNode,是一个主服务器,它用于管理文件系统名称空间并管理客户端对文件的访问。NameNode执行文件系统命名空间操作,如打开,关闭和重命名文件和目录。 它还确定块到DataNode的映射。 NameNode是所有HDFS元数据的仲裁者和存储库。 该系统的设计方式是用户数据永远不会流经NameNode。NameNode控制着关于blocks复制的所有决定。它周期性地接收集群中DataNode发送的心跳和块报告。收到心跳意味着DataNode在正常地运行着。一个块报告包含着DataNode上所有块信息的集合。
  • DataNode的工作:通常是群集中的每个节点一个DataNode,用于管理连接到它们所运行的节点的存储。 HDFS公开文件系统名称空间并允许用户数据存储在文件中。 在内部,文件被分成一个或多个块,这些块存储在一组DataNode中。 DataNode负责提供来自文件系统客户端的读取和写入请求。 DataNode还根据来自NameNode的指令执行数据块创建,删除和复制。
  • namenode的容错:(1)第一种机制是备份那些组成文件系统元数据持久状态的文件。这些写操作是实时同步的,是原子操作。(2)另一种可信的办法是运行一个辅助namenode,但它不能被用作namenode。这个辅助namenode的重要作用是定期通过编辑日志合并命名空间镜像,以防止编辑日志过大。但是,辅助namenode保存的状态总是滞后于主节点,所以在主节点全部失效时,难免会丢失部分数据。
  • namenode的高可用性:通过配置了一对活动-备用(active-standby)namenode。当活动namenode失效,备用namenode就会接管他的任务并开始服务于来自客户端的请求,不会有任何明显中断。

副本选址策略

namenode如何选择在那个datanode存储副本,这里需要对可靠性、写入带宽和读取带宽进行权衡。
副本的选址对HDFS的可靠性和性能是起到关键作用的。机架感知副本配置策略的目的是提高可靠性、可用性和网络带宽的利用率。运行在集群计算机的大型HDFS实例一般是分布在许多机架上。两个不同机架上的节点的通讯必须经过交换机。在大多数情况下,同一个机架上的不同机器之间的网络带宽要优于不同机架上的机器的。
通常情况下,当复制因子为3时,HDFS的副本放置策略是将一个副本放在本机架的一个节点上,将另一个副本放在本机架的另一个节点,最后一个副本放在不同机架的不同节点上。该策略减少机架内部的传输以提高写的性能。这个策略提高了写性能而不影响数据可靠性和读性能。为了最大限度地减少全局带宽消耗和读取延迟,HDFS试图让读取者的读取需求离副本最近。

 

HDFS不擅长的事情

  1. 低时间延迟的数据访问:要求低时间延迟数据访问的应用,例如几十毫秒范围,不适合在HDFS上运行。目前,对于低延迟的访问需求,HBase是更好的选择。

  2. 大量的小文件:由于namenode将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件总数受限于namenode的内存容量。
  3. 多用户写入,任意修改文件:他不支持具有多个写入者的操作,也不支持在文件的任意位置进行修改。

安全模式

在启动时,NameNode进入一个特殊的状态称之为安全模式。当NameNode进入安全模式之后数据块的复制将不会发生。NameNode接收来自DataNode的心跳和数据块报告。数据块报告包含正在运行的DataNode上的数据块信息集合。每个块都指定了最小副本数。一个数据块如果被NameNode检查确保它满足最小副本数,那么它被认为是安全的。
NameNode存储着HDFS的命名空间。NmaeNode使用一个称之为EditLog的事务日志持续地记录发生在文件系统元数据的每一个改变。NameNode在它本地的系统中用一个文件来存储EditLog。整个文件系统命名空间,包括blocks的映射关系和文件系统属性,将储存在一个叫FsImage的文件。FsImage也是储存在NameNode所在的本地文件系统中。
NameNode在内存中保存着整个文件系统命名空间的图像和文件映射关系。当Namenode启动时,它从硬盘中读取Edits和FsImage,将所有Edits中的事务作用在内存中的FsImage上,并将这个新版本的FsImage从内存中保存到本地磁盘上,然后删除旧的Edits,因为这个旧的Edits的事务都已经作用在FsImage上了。这个过程称为一个检查点(checkpoint)。只有当NameNode启动时会执行一次。

三.HDFS机制

心跳机制

namenode怎么 知道datanode的存活状态?datanode每隔一定时间向namenode发送一次心跳报告,目的就是告诉namenode自己的存活状态。
这个时间间隔默认是3秒,在hdfs-default.xml中设置,由参数dfs.heartbeat.interval:


  dfs.heartbeat.interval
  3
  Determines datanode heartbeat interval in seconds.

namenode什么时候判定datanode死亡?
datanode每隔3秒向namenode发送心跳报告,如果namenode连续10次没有收到datanode的心跳报告,则认为datanode可能死了,但是并没有断定其死亡(namenode还需去验证)。这个时候,namenode向datanode发送一次检查,发送一次检查的时间是5min,如果一次检查没有返回信息,namenode还会再进行一次检查,如果再没有收到信息,namenode就认为该datanode死亡。
所以,namenode最终判断datanode死亡(宕机)需要103+560*2 = 630秒。


四.读流程

Hadoop-HDFS 基础回顾_第1张图片

  1. 打开分布式文件:调用分布式文件 DistributedFileSystem.open( ) 方法;
  2. 寻址请求:从 NameNode 处得到 DataNode 的地址,DistributedFileSystem使用 RPC 方式调用了NameNode,NameNode 返回存有该副本的DataNode 地址,DistributedFileSystem 返回了一个输入流对象(FSDataInputStream),该对象封装了输入流 DFSInputStream;
  3. 连接到DataNode:调用输入流 FSDataInputStream.read( ) 方法从而让DFSInputStream 连接到 DataNodes;
  4. 从 DataNode 中获取数据:通过循环调用 read( ) 方法,从而将数据从 DataNode 传输到客户端;
  5. 读取另外的 DataNode 直到完成:到达块的末端时候,输入流 DFSInputStream 关闭与 DataNode 连接, 寻找下一个 DataNode;
  6. 完成读取,关闭连接:即调用输入流 FSDataInputStream.close( );

     容错

     读的过程中,有可能失败的原因:

  1. 要读取的 DataNode 存在故障,导致连接不上
  2. 读取 block 时,进行 checksum 验证不通过

     这两种情况,都会从 block 的其他备份所在的 DataNode 继续读取数据,不过如果是 block 出问题还会上报给 NameNode,         NameNode 会标记该 block 已经损坏,然后复制 block 达到预期设置的文件备份数 。

 

五.写流程

Hadoop-HDFS 基础回顾_第2张图片

  1. 客户端调用 DistributedFileSystem 的 create() 方法,开始创建新文件:DistributedFileSystem 创建 DFSOutputStream,产生一个 RPC 调用,让 NameNode 在文件系统的命名空间中创建这一新文件;
  2. NameNode 接收到用户的写文件的 RPC 请求后,先要执行各种检查,如客户是否有相关的创建权限和该文件是否已存在等,检查都通过后才会创建一个新文件,并将操作记录到编辑日志,然后 DistributedFileSystem会将 DFSOutputStream 对象包装在 FSDataOutStream 实例中,返回客户端;否则文件创建失败并且给客户端抛 IOException。
  3. 客户端开始写文件:DFSOutputStream 会将文件分割成 packets 数据包(一般为 64K),然后将这些 packets 写到其内部的一个叫做 data queue(数据队列)。data queue 会向 NameNode 节点请求适合存储数据副本的 DataNode 节点的列表,然后这些 DataNode 之前生成一个 Pipeline 数据流管道,我们假设副本集参数被设置为 3,那么这个数据流管道中就有 3 个 DataNode 节点。
  4. 首先 DFSOutputStream 会将 packets 向 Pipeline 数据流管道中的第一个 DataNode 节点写数据,第一个DataNode 接收 packets 然后把 packets 写向 Pipeline 中的第二个节点,同理,第二个节点保存接收到的数据然后将数据写向 Pipeline 中的第三个 DataNode 节点。
  5. DFSOutputStream 内部同样维护另外一个内部的写数据确认队列—— ack queue 。当 Pipeline 中的第三个 DataNode 节点将 packets 成功保存后,该节点回向第二个 DataNode 返回一个确认数据写成功的信息,第二个 DataNode 接收到该确认信息后在当前节点数据写成功后也会向 Pipeline 中第一个 DataNode 节点发送一个确认数据写成功的信息,然后第一个节点在收到该信息后如果该节点的数据也写成功后,会将 packets 从 ack queue 中将数据删除。
  6. 完成写操作后,客户端调用 close() 关闭写操作,刷新数据;
  7. 在数据刷新完后 NameNode 后关闭写操作流。到此,整个写操作完成。

     简单总结如下:

  1. 客户端调用 create 方法,RPC 调用 NameNode 在命名空间中创建文件;
  2. NameNode 做权限和文件存在检查,通过则创建文件并写日志,否则返回异常;
  3. 将文件分割为数据包并写入 data queue,向 NameNode 请求将要写入的 DataNode 节点并生成一个 pipeline;
  4. 依次向 pipeline 中的每一个 DataNode 节点写数据;
  5. 同时维护一个 ack queue,写入成功则从队列中移除;
  6. 调用 close 方法,刷新数据;
  7. 关闭流。

     容错

      在写数据的过程中,如果其中一个 DataNode 节点写失败了会怎样?

     1) 管道关闭。

     2)正常的datanode上的当前block会有一个新ID,并将该ID传送给namenode,以便失败的datanode在恢复后可以删除那个不完整的block。

    3) 失败的datanode会被移出管道,余下的数据块继续写入管道的其他两个正常的datanode。

    4) namenode会标记这个block的副本个数少于指定值。block的副本会稍后在另一个datanode创建。

     5)有些时候多个datanode会失败,但非常少见。只要dfs.replication.min(缺省是1)个datanode成功了,整个写入过程就算成功。缺少的副本会在集群中异步的复制,直到达到正常的副本数。

     6. 当client完成了所有block的写入后,调用FSDataOutputStream的close()方法关闭文件。

      7. FSDataOutputStream通知namenode写文件结束。

 

六.HDFS数据完整性


用户肯定都希望系统在存储和处理数据时,数据不会有任何丢失或损坏。但是,受网络不稳定、硬件损坏等因素,IO操作过程中难免会出现数据丢失或脏数据,难免会出现数据丢失或脏数据,数据传输的量越大,出现错误的概率就越高。

检测数据是否损坏的常见措施是,在数据第一次引入系统时计算校验和(checksum)并存储,在数据进行传输后再次计算校验和进行对比,如果计算所得的新校验和和原来的校验和不匹配,就认为数据已损坏。但该技术并不能修复数据——它只能检测出数据错误。(这正是不使用低端硬件的原因。具体说来,一定要使用ECC内存。)注意,校验和也是可能损坏的,不只是数据,但由于校验和比数据小得多,所以损坏的可能性非常小。

(1)对本地文件I/O的检查
在Hadoop中,本地文件系统的数据完整性由客户端负责。重点在于存车读取文件时进行校验和的处理。
具体做法是:每当hadoop创建文件a时,hadoop就会同时在同一个文件夹下创建隐藏文件.a.crc,这个文件记录了 文件a的校验和。针对数据文件的大小,每512个字节会生成一个32位的校验和(4字节),可以在src/core/core-default.xml中通过修改io.bytes.per.checksum的大小来修改每个校验和所针对的文件的大小。

在hadoop中,校验和系统单独为一类,org.apache.hadoop.fs.ChecksumFileSystem,当需要校验和机制时,可以很方便的调用它来服务。

(2)对HDFS的I/O数据进行检查

一般来说,HDFS会在三种情况下检验校验和:

DataNode接收数据后存储数据前
DataNode接收数据一般有两种情况:1.从客户端上传数据 2.DataNode从其他DataNode上接收数据。
当客户端上传数据时,正在写数据的客户端将数据及其校验和发送到由一系列datanode组成的Pipeline管线。Pipeline管线中最后一个datanode负责验证校验和。

DataNode数据存储步骤:(包括从DataNode和客户端两种传输方式)
1.在传输数据的最开始阶段,Hadoop会简单地检查数据块的完整性信息;
2.依次向各个DataNode传输数据,包括数据头信息、块信息、备份个数、校验和等;
3.Hadoop不会在数据每流动到一个DataNode都检查校验和,只会在数据流达到最后一个节点时才检查校验和
如果在验证过程中发现有不一致的块,就会抛出CheckSumException异常信息

客户端读取DataNode上的数据时
Hadoop会在客户端读取DataNode上的数据时,使用DFSClient中的read函数先将数据读入到用户的数据缓冲区,然后再检查校验和。将他们与datanode中存储的校验和进行比较
每个datanode均持久保存有一个用于验证的校验和日志,所以它知道每个数据块的最后一次验证时间
客户端成功验证一个数据块后,会告诉这个datanode,datanode由此更新日志

DataNode后台守护进程的定期检查
DataNode会在后台运行DataBlockScanner,这个程序定期验证存储在这个datanode上的所有数据块(3周)
该项措施是解决物理存储媒体上位衰减,位损坏的有力措施。

Hadoop处理损坏数据的机制:

DataNode在读取block块的时候会先进行checksum(数据块校验和)
如果client发现本次计算的校验和跟创建时的校验和不一致,则认为该block块已损坏
客户端在抛出ChecksumException之前上报该block信息给namenode进行标记(“已损坏”)
这样namenode就不会把客户端指向这个block,也不会复制这个block到其他的datanode。
client重新读取另外的datanode上的block
在心跳返回时NameNode将块的复制任务交给DataNode,从完好的block副本进行复制以达到默认的备份数3
NameNode删除掉坏的block。
DataNode在一个block块被创建之日起三周后开始进行校验
如果出于一些原因在操作的时候不想让hdfs检查校验码

在FileSystem的open()之前通过设置FileSystem的setVerifyCheckSum(false)方法禁用校验和
或者命令行使用get时候添加选项-ignoreCrc或者直接使用-copyToLocal
    fs.setVerifyChecksum(false)   fs.open(new Path(“”)) // 就不进行校验检查了
    Hadoop fs –get –ignoreCrc hdfs://master:9000/a.txt
    Hadoop fs –copyToLocal hdfs://master:9000/a.txt

CheckSum校验原理
Hadoop数据的完整性检测,都是通过校验和的比较来完成,在创建新文件时(也就是在上传数据到hdfs上时)将校验和的值和数据一起保存起来。NameNode会收到来自client、DataNode的检验和信息,根据这两个信息来维护文件的块存储及向客户端提供块读取服务。

HDFS会对写入的所有数据计算校验和,并在读取数据时验证校验和。
常用的错误检测码是CRC-32(循环冗余校验),任何大小的数据输入均计算得到一个32位的整数校验和。
在写入文件时,hdfs为每个数据块都生成一个crc文件。客户端读取数据时生成一个crc与数据节点存储的crc做比对,如果不匹配则说明数据已经损坏了。数据节点在后台运行一个程序定期(默认为21天)检测数据,防止物理存储介质中位衰减而造成的数据损坏。

DataNode在写入时计算出校验和,然后每次读的时候再计算校验和进行检验
hdfs会为每一个固定长度的数据(一个个数据包)执行一次校验和
这个值由io.bytes.per.checksum指定,默认是512字节。
因为CRC32是32位即4个字节,这样校验和占用的空间就会少于原数据的1%。

datanode在存储收到的数据前会校验数据的校验和,比如收到客户端的数据或者其他副本传过来的数据。
如hdfs数据流中客户端写入数据到hdfs时的数据流,在管道的最后一个datanode会去检查这个校验和
如果发现错误,就会抛出ChecksumException到客户端

从datanode读数据的时候一样要检查校验和,而且每个datanode还保存了检查校验和的日志,每次校验都会记录到日志中

除了读写操作会检查校验和以外,datanode还跑着一个后台进程(DataBlockScanner)
定期校验存在在它上面的block,因为除了读写过程中会产生数据错误以外,硬件本身也会产生数据错误,比如位衰减(bit rot)
 

 

 

你可能感兴趣的:(hadoop)