HDFS 原理解析

源自https://www.cnblogs.com/duanxz/p/3874009.html

Namenode是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表, 接收用户的操作请求。
文件包括:
①fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息。
②edits:操作日志文件。
③fstime:保存最近一次checkpoint的时间
以上这些文件是保存在linux的文件系统中。通过hdfs-site.xml的dfs.namenode.name.dir属性进行设置。

<property>
    <name>dfs.name.dir</name>
    <value>file:///root/hadoop/hdfs/name</value>
</property>
<property>
    <name>dfs.data.dir</name>
    <value>file:///root/hadoop/hdfs/data</value>
</property>

查看:

[root@host ~]# cd /root/hadoop/hdfs/name/current/
[root@host current]# ls |grep fsimage
fsimage_0000000000000136979
fsimage_0000000000000136979.md5

查看NameNode的fsimage与edits内容

这个两个文件中的内容使用普通文本编辑器是无法直接查看的,幸运的是hadoop为此准备了专门的工具用于查看文件的内容,这些工具分别为oev和oiv,可以使用hdfs调用执行。

启动服务器:bin/hdfs oiv -i 某个fsimage文件

[root@host current]# hdfs oiv -i fsimage_0000000000000136979
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/root/hadoop/hadoop-2.7.4/share/hadoop/common/lib/slf4j-log4j12-1.7.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/root/hive/apache-hive-2.1.1/lib/log4j-slf4j-impl-2.4.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
18/09/28 17:16:28 INFO offlineImageViewer.FSImageHandler: Loading 2 strings
18/09/28 17:16:28 INFO offlineImageViewer.FSImageHandler: Loading 1627 inodes.
18/09/28 17:16:28 INFO offlineImageViewer.FSImageHandler: Loading inode references
18/09/28 17:16:28 INFO offlineImageViewer.FSImageHandler: Loaded 0 inode references
18/09/28 17:16:28 INFO offlineImageViewer.FSImageHandler: Loading inode directory section
18/09/28 17:16:28 INFO offlineImageViewer.FSImageHandler: Loaded 636 directories
18/09/28 17:16:28 INFO offlineImageViewer.WebImageViewer: WebImageViewer started. Listening on /127.0.0.1:5978. Press Ctrl+C to stop the viewer.

导出fsimage的内容:

[root@host current]# hdfs oiv -p XML -i fsimage_0000000000000136979 -o /root/fsimage.xml

[root@host ~]# ls |grep fs*.xml
fsimage.xml

[root@host ~]# more fsimage.xml
<?xml version="1.0"?>
<fsimage><NameSection>
<genstampV1>1000</genstampV1><genstampV2>13492</genstampV2><genstampV1Limit>0</genstampV1Limit><lastAllocatedBlockId>1073754287</lastAllocatedBlockId><txid>136979</txid></NameSe
ction>
<INodeSection><lastInodeId>39058</lastInodeId><inode><id>16385</id><type>DIRECTORY</type><name></name><mtime>1535523351312</mtime><permission>root:supergroup:rwxr-xr-x</permissi
on><nsquota>9223372036854775807</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16386</id><type>DIRECTORY</type><name>user</name><mtime>1528099505418</mtime><permission>root:supergroup:rwx-wx-wx</permission><nsquota>-1</nsquota><dsquota>-1</dsquo
ta></inode>
<inode><id>16387</id><type>DIRECTORY</type><name>hive</name><mtime>1505113438228</mtime><permission>root:supergroup:rwx-wx-wx</permission><nsquota>-1</nsquota><dsquota>-1</dsquo
ta></inode>
<inode><id>16388</id><type>DIRECTORY</type><name>tmp</name><mtime>1504694912242</mtime><permission>root:supergroup:rwx-wx-wx</permission><nsquota>-1</nsquota><dsquota>-1</dsquot
a></inode>
<inode><id>16389</id><type>DIRECTORY</type><name>root</name><mtime>1505099266188</mtime><permission>root:supergroup:rwx------</permission><nsquota>-1</nsquota><dsquota>-1</dsquo
ta></inode>
<inode><id>16400</id><type>DIRECTORY</type><name>tmp</name><mtime>1537945135504</mtime><permission>root:supergroup:rwx-wx-wx</permission><nsquota>-1</nsquota><dsquota>-1</dsquot
a></inode>
<inode><id>16401</id><type>DIRECTORY</type><name>hive</name><mtime>1509612138628</mtime><permission>root:supergroup:rwx-wx-wx</permission><nsquota>-1</nsquota><dsquota>-1</dsquo
ta></inode>
<inode><id>16402</id><type>DIRECTORY</type><name>root</name><mtime>1538037033357</mtime><permission>root:supergroup:rwx------</permission><nsquota>-1</nsquota><dsquota>-1</dsquo
ta></inode>

................................................

查看edtis的内容

 [root@host current]# hdfs oev -p XML -i edits_0000000000000136980-0000000000000137005 -o /root/fsimage.xml

[root@host ~]# more edits.xml
<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
  <EDITS_VERSION>-63</EDITS_VERSION>
  <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>136980</TXID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>136981</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>39059</INODEID>
      <PATH>/hbase/WALs/host,16201,1538035936482/host%2C16201%2C1538035936482.1538122348562</PATH>
      <REPLICATION>1</REPLICATION>

...............................................................

元信息的持久化

在NameNode中存放元信息的文件是 fsimage。在系统运行期间所有对元信息的操作都保存在内存中并被持久化到另一个文件edits中。并且edits文件和fsimage文件会被SecondaryNameNode周期性的合并(合并过程会在SecondaryNameNode中详细介绍)。

NameNode特点

运行NameNode会占用大量内存和I/O资源,一般NameNode不会存储用户数据或执行MapReduce任务。

为了简化系统的设计,Hadoop只有一个NameNode,这也就导致了hadoop集群的单点故障问题。因此,对NameNode节点的容错尤其重要,hadoop提供了如下两种机制来解决:

  • 将hadoop元数据写入到本地文件系统的同时再实时同步到一个远程挂载的网络文件系统(NFS)。
  • 运行一个secondary NameNode,它的作用是与NameNode进行交互,定期通过编辑日志文件合并命名空间镜像,当NameNode发生故障时它会通过自己合并的命名空间镜像副本来恢复。需要注意的是secondaryNameNode保存的状态总是滞后于NameNode,所以这种方式难免会导致丢失部分数据(后面会详细介绍)。

SecondaryNameNode

需要注意,SecondaryNameNode并不是NameNode的备份。我们从前面的介绍已经知道,所有HDFS文件的元信息都保存在NameNode的内存中。在NameNode启动时,它首先会加载fsimage到内存中,在系统运行期间,所有对NameNode的操作也都保存在了内存中,同时为了防止数据丢失,这些操作又会不断被持久化到本地edits文件中。

edits文件存在的目的是为了提高系统的操作效率,NameNode在更新内存中的元信息之前都会先将操作写入edits文件。在NameNode重启的过程中,edits会和fsimage合并到一起,但是合并的过程会影响到Hadoop重启的速度,SecondaryNameNode就是为了解决这个问题而诞生的。

SecondaryNameNode的角色就是定期的合并edits和fsimage文件,我们来看一下合并的步骤:

  1. 合并之前告知NameNode把所有的操作写到新的edites文件并将其命名为edits.new。
  2. SecondaryNameNode从NameNode请求fsimage和edits文件
  3. SecondaryNameNode把fsimage和edits文件合并成新的fsimage文件
  4. NameNode从SecondaryNameNode获取合并好的新的fsimage并将旧的替换掉,并把edits用第一步创建的edits.new文件替换掉
  5. 更新fstime文件中的检查点

最后再总结一下整个过程中涉及到NameNode中的相关文件

  • fsimage :保存的是上个检查点的HDFS的元信息
  • edits :保存的是从上个检查点开始发生的HDFS元信息状态改变信息
  • fstime:保存了最后一个检查点的时间戳

2、Datanode

提供真实文件数据的存储服务。 DataNode是hdfs中的worker节点,它负责存储数据块,也负责为系统客户端提供数据块的读写服务,同时还会根据NameNode的指示来进行创建、删除、和复制等操作。此外,它还会通过心跳定期向NameNode发送所存储文件块列表信息。当对hdfs文件系统进行读写时,NameNode告知客户端每个数据驻留在哪个DataNode,客户端直接与DataNode进行通信,DataNode还会与其它DataNode通信,复制这些块以实现冗余。

文件块( block): 最基本的存储单位。 对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。 HDFS默认Block大小是128MB, 因此,一个256MB文件,共有256/128=2个Block. 与普通文件系统不同的是,在 HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间。 Replication:多复本。默认是三个。通过hdfs-site.xml的dfs.replication属性进行设置。

二、数据备份

HDFS通过备份数据块的形式来实现容错,除了文件的最后一个数据块外,其它所有数据块大小都是一样的。数据块的大小和备份因子都是可以配置的。NameNode负责各个数据块的备份,DataNode会通过心跳的方式定期的向NameNode发送自己节点上的Block 报告,这个报告中包含了DataNode节点上的所有数据块的列表。

文件副本的分布位置直接影响着HDFS的可靠性和性能。一个大型的HDFS文件系统一般都是需要跨很多机架的,不同机架之间的数据传输需要经过网关,并且,同一个机架中机器之间的带宽要大于不同机架机器之间的带宽。如果把所有的副本都放在不同的机架中,这样既可以防止机架失败导致数据块不可用,又可以在读数据时利用到多个机架的带宽,并且也可以很容易的实现负载均衡。但是,如果是写数据,各个数据块需要同步到不同的机架,会影响到写数据的效率。

而在Hadoop中,如果副本数量是3的情况下,Hadoop默认是这么存放的,把第一个副本放到机架的一个节点上,另一个副本放到同一个机架的另一个节点上,把最后一个节点放到不同的机架上。这种策略减少了跨机架副本的个数提高了写的性能,也能够允许一个机架失败的情况,算是一个很好的权衡。

关于副本的选择,在读的过程中,HDFS会选择最近的一个副本给请求者。

三、HDFS中的沟通协议

  所有的HDFS中的沟通协议都是基于tcp/ip协议,一个客户端通过指定的tcp端口与NameNode机器建立连接,并通过ClientProtocol协议与NameNode交互。而DataNode则通过DataNode Protocol协议与NameNode进行沟通。HDFS的RCP(远程过程调用)对ClientProtocol和DataNode Protocol做了封装。按照HDFS的设计,NameNode不会主动发起任何请求,只会被动接受来自客户端或DataNode的请求。

四、可靠性保证

可以允许DataNode失败。DataNode会定期(默认3秒)的向NameNode发送心跳,若NameNode在指定时间间隔内没有收到心跳,它就认为此节点已经失败。此时,NameNode把失败节点的数据(从另外的副本节点获取)备份到另外一个健康的节点。这保证了集群始终维持指定的副本数。

可以检测到数据块损坏。在读取数据块时,HDFS会对数据块和保存的校验和文件匹配,如果发现不匹配,NameNode同样会重新备份损坏的数据块。

原文地址:https://www.cnblogs.com/playforever/p/9719827.html