HDFS细节描述

| 标签 Hadoop  HDFS 

1. 基本概述

1.HDFS本身是一个典型的MS结构的框架:主节点NameNode,从节点DataNode -通过slaves文件来指定从节点,HDFS的主节点通过hdfs-site.xml来指定 ​

2.HDFS对会上传的数据进行切分,切成数据块(Block)来存储到不同的DataNode上 ​

3.HDFS会对存储的数据来进行备份,每一个备份称之为是一个副本(replication/replicas)。副本策略默认为3 ​

4.NameNode需要记录元数据(metadata),元数据就类似于账本 ​

5.HDFS仿照Linux设计了一套文件系统,允许将文件存储在不同的虚拟路径下,根路径是/ ​

2. block

1.Block是HDFS中数据存储的基本形式,即任意一个文件存储到HDFS上之后都是以Block形式来存储 ​

2.在Hadoop2.0中,Block的大小默认是128M,可以通过dfs.blocksize来进行调节,单位是字节,放在hdfs-site.xml中 ​

3.如果一个文件不足一个Block的默认大小,那么这个文件放到HDFS上之后,文件本身是多大就占多大的地方,对应的Block也是文件的实际大小 ​

4.HDFS会为每一个Block分配一个唯一的Block ID ​

5.HDFS会为每一个Block分配一个递增的Generation Stamp ​

Block类,它含有三个成员:blockId,numBytes和generationStamp。numBytes即block的大小,而另外两个分别是什么呢?blockId是block的标识符,可以从block文件名中看到,例如${hadoop.tmp.dir}/dfs/data/current/blk_826540629399449945,这一串数字就是blockId。同目录下另一个meta文件,如blk_826540629399449945_1017.meta,1017即是generationStamp。从Block类本身可以看到,generationStamp在compare、equals等操作上起到一个对blockId的辅助作用,由此猜测多个blocks可能拥有相同的blockId,彼此的generationStamp不同。 ​

6.HDFS切块的意义

  • 能够存储超大文件
  • 能够快速的备份

3. NameNode

1.NameNode是HDFS中的主节点,默认情况下HDFS中,NameNode只有一个 ​

2.作用:记录元数据,管理DataNode ​

3.元数据是描述数据的数据,可以理解为是一个账本 ​

4.HDFS中的元数据主要包含

  • 文件的上传路径
  • 上传用户
  • 文件的权限
  • 文件大小
  • Block大小
  • 文件和BlockID的映射关系
  • Block的Genertion Stamp
  • BlockID和DataNode的映射关系
  • 副本数量

5.NameNode将元数据维系在内存以及磁盘中

  • 维系在内存中的目的是为了读写快
  • 维系在磁盘中的目的是为了持久化

6.元数据在磁盘上的存储路径由属性hadoop.tmp.dir来决定,这个属性是放在core-site.xml中。如果不指定,那么默认是放在/tmp下 ​

7.和元数据相关的文件

  • edits:操作文件。记录NameNode接收的每一个写请求
  • fsimage:元映像文件。记录元数据的,但是注意,这个文件中的元数据和内存中的元数据并不是同步的

8.当NameNode收到写请求的时候,会先将写请求这个命令本身记录到edits_inprogress文件中,如果记录成功更新内存中的元数据。如果内存中的元数据更新成功,就会给客户端返回ack信号。注意,此时fsimage文件中的元数据并没有修改 ​

9.当达到指定条件之后,edits_inprogress文件会产生滚动,滚动生成一个新的edits_inprogress,原来的edits_inprogress会自动重命名为edits文件,HDFS会将edits文件中记录的命令取出来一一执行更新到fsimage文件中,修改fsimage中的元数据 ​

10.edits_inprogress文件的滚动条件 ​

  • 空间:当edits_inprogress文件达到指定大小(默认是64M,可以通过fs.checkpoint.size来调节,单位是字节,放在core-site.xml中)的时候,会产生滚动

  • 时间:当距离上一次滚动的时间达到指定间隔(默认是60min,可以通过fs.checkpoint.period来调节,单位是s)的时候,edits_inprogress文件也会产生滚动。注意,Hadoop第一次启动的时候,启动1min之后edits_inprogress自动的滚动一次

  • 重启:当NameNode重启的时候,edits_inprogress文件也会自动滚动

  • 强制:利用hadoop dfsadmin -rollEdits来强制滚动

11.NameNode通过心跳机制来管理DataNode - DataNode定时向NameNode发送心跳信息 ​

12.DataNode每隔3s(通过dfs.heartbeat.interval来调节,单位是s,放在hdfs-site.xml中)向NameNode发送一次心跳,当NameNode超过10min没有收到DataNode的心跳,那么就认为这个DataNode已经lost(丢失),这个时候NameNode会将这个DataNode上的数据备份到其他节点上来保证副本数量 ​

13.心跳信息 ​

a.DataNode的状态(预服役、服役、预退役) ​

b.clusterid:集群编号 ​
  • 在对NameNode进行格式化(hadoop namenode -format)的时候,会自动计算产生一个clusterid
  • 每次格式化都会重新计算产生一个新的clusterid
  • 当HDFS集群启动的时候,NameNode在接收第一次心跳的时候,会将clusterid在心跳响应中分发给每一个 DataNode
  • 当DataNode收到clusterid之后就不会再次接收新的clusterid了
  • DataNode每一次通信都会携带clusterid,当NameNode收到DataNode的信息的时候会先校验clusterid是否一致。如果不一致则直接拒绝;如果一致才会处理这个DataNode的请求
  • 多次格式化,会导致NameNode或者DataNode启动不了

c.DataNode存储的Block信息 ​

4. HDFS写数据流程

image

1、使用HDFS 提供的客户端 Client,向远程的 namenode 发起 RPC 请求 ​

2、namenode 会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功则会为文件创建一个记录,否则会让客户端抛出异常; ​

3、当客户端开始写入文件的时候,客户端会将文件切分成多个 packets,并在内部以数据队列“data queue(数据队列)”的形式管理这些 packets,并向 namenode 申请 datanode列表,获取用来存储 replicas 的合适的 datanode 列表,列表的大小根据 namenode 中 replication的设定而定; ​

4、开始以 pipeline(管道)的形式将 packet 写入所有的 replicas 中。客户端把 packet 以流的方式写入第一个 datanode,该 datanode 把该 packet 存储之后,再将其传递给在此 pipeline中的下一个 datanode,直到最后一个 datanode,这种写数据的方式呈流水线的形式。 ​

5、最后一个 datanode 成功存储之后会返回一个 ack packet(确认队列),在 pipeline 里传递至客户端,在客户端的开发库内部维护着”ack queue”,成功收到 datanode 返回的 ackpacket 后会从”data queue”移除相应的 packet。 ​

6、如果传输过程中,有某个 datanode 出现了故障,那么当前的 pipeline 会被关闭,出现故障的 datanode 会从当前的 pipeline 中移除,剩余的 block 会继续剩下的 datanode 中继续以 pipeline 的形式传输,同时 namenode 会分配一个新的 datanode,保持 replicas 设定的数量。 ​

7、客户端完成数据的写入后,会对数据流调用 close()方法,关闭数据流; ​

8、只要写入了 dfs.replication.min(最小写入成功的副本数)的副本数(默认为 1),写操作就会成功,并且这个块可以在集群中异步复制,直到达到其目标复本数(dfs.replication的默认值为 3),因为 namenode 已经知道文件由哪些块组成,所以它在返回成功前只需要等待数据块进行最小量的复制。 ​

5. HDFS读数据流程

image

1、使用 HDFS 提供的客户端 Client,向远程的 namenode 发起 RPC 请求; ​

2、namenode 会视情况返回文件的全部 block 列表,对于每个 block,namenode 都会返回有该 block 拷贝的 datanode 地址; ​

3、客户端Client会选取离客户端最近的datanode来读取block;如果客户端本身就是datanode,那么将从本地直接获取数据; ​

4、读取完当前 block 的数据后,关闭当前的 datanode 链接,并为读取下一个 block 寻找最佳的 datanode; ​

5、当读完列表 block 后,且文件读取还没有结束,客户端会继续向 namenode 获取下一批的block 列表; ​

6、读取完一个 block 都会进行 checksum 验证,如果读取 datanode 时出现错误,客户端会通知 namenode,然后再从下一个拥有该 block 拷贝的 datanode 继续读。 ​


上一篇     下一篇