HDFS作为一个分布式文件系统,和传统文件系统相比它面临着以下几个新的挑战:
1. 它需要能够存取大于一个单机容量的文件。
2. 它需要能够对分布式计算做到支持:也就是能将文件分成多个部分存储到不同的节点,以便多个节点能同时对文件多个部分并行进行计算。
3. 它需要能够应对集群中节点失效的问题。在集群中节点失效很普遍。这是系统设计必须考虑的问题。

分块存储

有多个原因让HDFS选择了分块存储:
1. 分块存储让一个大的文件可以放分块存放在多个节点。
2. 分块让分布式计算更加方便。文件被分成多个块,不同的块在不同的节点。可以多个节点同时对文件的不同块并行计算。

分块的大小

HDFS内对于一个文件可以设置文件分块的大小。但是对于一个文件一旦设置了分块的大小,它除了最后一个块,所有的块的大小都是一样的。这让文件管理变得方便。一个文件对于HDFS来说,可以表示为一个块号的序列。HDFS默认的文件分块大小目前是128M,之前版本里是64M。对于文件的最后一个块,不足分一个块大小的,只会占用它实际大小的磁盘空间,并不会占用一个完整块的大小。

关于分块大小的权衡

分块越小,越利于分布式计算。理论上并行度越高。但是分块越多,对于文件的管理就越难。因为当用户查询一个文件的时候,你必须找到它所有的块,以及他们的读写顺序。每个块对应HDFS集群上一个节点上的一个磁盘上的文件。块越小,就意味着要打开和关闭的文件越多。所以这也是一个权衡。

文件的冗余备份

对一个集群来说,一个节点因为硬件或者网络的问题而不可用,是很正常的情况。如果每个文件的数据块在集群里都是只有一份的话,那很多情况下是不能接受的。对于一个分布式系统来说,容错性是很重要的。因为在HDFS里文件是被分成块来存储的。只要对块进行冗余备份,就可以达到整个系统的容错。一个数据块在HDFS里默认会被存3份。并且系统发现一个数据块的备份数少于3时,会自动启动备份功能。除非3个备份同时失效,否则数据就是安全的。假如你的Hadoop集群的机器分布在不同的机架上,通过配置,Hadoop会知道哪些节点在不同的机架上,从而在备份时会把备份数据放到不同的机架上。

主节点NameNode和从节点DataNode

存在HDFS里的文件被分成块,分散在集群里的不同节点。所以我们需要有一个节点来维护整个文件系统目录结构以及文件和文件对应的块在集群里的位置。并且这个节点来对外提供文件读写服务。它是整个集群的主节点,在HDFS叫做NameNode。它负责维护这个文件系统的目录结构。并且维护着文件和文件对应块在集群位置的关系表。
在HDFS里只负责存储数据的节点,叫做DataNode。它负责存储NameNode分配过来的块。DataNode并不关心一个文件的整体,它只负责存储数据块。

NameNode需要存储整个文件系统的目录结构,它需要知道当前HDFS里有哪些目录,哪些文件。还有一个文件是由哪些数据块构成的,以及这些块存储在哪些DataNode里。
对于文件系统的目录结构以及文件是由哪些数据块构成的,NameNode是存储在两个文件里的fsimage和edits文件里。按照我们之前的安装配置,他们的位置是NameNode的 /opt/hadoop/tmp/dfs/name/current 目录下。
fsimage存储着系统上次检查点时的目录结构。NameNode启动的时候会把fsimage里的文件目录结构载入内存。这时NameNode内存里有一份HDFS的文件系统。然后client对文件系统的改动会被更新到内存里的文件系统,并同时写入edits文件。这时并不会更新fsimage文件。在NameNode下次启动的时候,会首先载入fsimage,然后把edits文件里对HDFS的修改重新回放一遍更新内存,并且写一个新的fsimage,删除掉edits文件。
edits_inprogress_* 文件存储着当前系统正在记录的edits文件。
通过下边的命令我们可以把一个edits文件转化为xml文件,来方便查看:


 hdfs oev -i edits_inprogress_0000000000000000086 -o edits.xml

我们看一下创建一个文件夹的操作:


 <RECORD>
    <OPCODE>OP_MKDIR</OPCODE>
    <DATA>
      <TXID>88</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16393</INODEID>
      <PATH>/home/mark</PATH>
      <TIMESTAMP>1514179610540</TIMESTAMP>
      <PERMISSION_STATUS>
        <USERNAME>root</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>493</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>

下边是添加一个文件在edits里增加的记录:


  <RECORD>
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>89</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16394</INODEID>
      <PATH>/test/small._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1514179951158</MTIME>
      <ATIME>1514179951158</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>      <CLIENT_NAME>DFSClient_NONMAPREDUCE_2023547768_1</CLIENT_NAME>
      <CLIENT_MACHINE>172.16.192.90</CLIENT_MACHINE>
      <OVERWRITE>true</OVERWRITE>
      <PERMISSION_STATUS>
        <USERNAME>root</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
      <ERASURE_CODING_POLICY_ID>0</ERASURE_CODING_POLICY_ID>
      <RPC_CLIENTID>200d2141-6833-48c1-b014-441d3607566f</RPC_CLIENTID>
      <RPC_CALLID>3</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
    <DATA>
      <TXID>90</TXID>
      <BLOCK_ID>1073741837</BLOCK_ID>
    </DATA>
  </RECORD>

通过下边的命令我们可以把一个fsiamge文件转化成xml文件,来阅读里边的内容:


hdfs oiv -p XML -i fsimage_0000000000000000095 -o fsimage.xml

这是一个目录在fsimage里的部分:


    <inode>
            <id>16386</id>
            <type>DIRECTORY</type>
            <name>test</name>
            <mtime>1514179951328</mtime>
            <permission>root:supergroup:0755</permission>
            <nsquota>-1</nsquota>
            <dsquota>-1</dsquota>
    </inode>

这是一个文件在fsimage里的部分,里边有文件的id,名字,备份数,分块大小,权限,生成时间,每个块的id,以及每个块的大小。


    <inode>
            <id>16391</id>
            <type>FILE</type>
            <name>big</name>
            <replication>3</replication>
            <mtime>1514169560684</mtime>
            <atime>1514169558381</atime>
                        <preferredBlockSize>134217728</preferredBlockSize>
                        <permission>root:supergroup:0644</permission>
                        <blocks>
                </block>
                <block>
                    <id>1073741834</id>
                    <genstamp>1010</genstamp>
                    <numBytes>134217728</numBytes>
                </block>
                <block>
                    <id>1073741835</id>
                    <genstamp>1011</genstamp>
                    <numBytes>134217728</numBytes>
                </block>
                <block>
                    <id>1073741836</id>
                    <genstamp>1012</genstamp>
                    <numBytes>12017936</numBytes>
                </block>
            </blocks>
            <storagePolicyId>0</storagePolicyId>

如果我们添加一个文件,随后删掉,那么这两次操作在edits文件里都会留下记录。但是在用这个edits更新过的fsimage里不会有变化。
通过上边的fsimage文件我们发现NameNode并没有保存文件的数据块和DataNode的对应关系。
edits文件里存储的是当前用户对HDFS文件系统的修改,最终是会合并到images文件里的。images文件里保存的是HDFS的静态信息:文件目录,文件名,文件权限,分块信息(块号和块的大小)。HDFS里的文件一旦创建,这些信息不会再产生变化,所以会以文件的形式存储在NameNode的本地文件里。而文件的块具体存放在哪些DataNode是动态的。会因为集群里的DataNode的故障而改变。即使存在NameNode的本地文件里也没有用,NameNode还是要时刻检查DataNode是否可用。所以一个文件的块具体存放在哪些DataNode是动态的信息。DataNode会定期把自己存储了哪些块报告给NameNode,NameNode然后根据集群里DataNode的报告维护一个文件块和DataNode对应关系表。这个表只在NameNode运行的时候存在NameNode的内存里。

对于NameNode的备份

从上边的介绍你可以看到,NameNode在整个系统中的作用非常重要,如果NameNode失效,那么整个HDFS就将瘫痪。那么对于NameNode的备份,HDFS提出了好几个解决方案:

Secondary NameNode

因为NameNode只有在启动的时候才会将edits 文件里用户的操作写入images里。并且更新images文件。如果edits文件非常大的话NameNode在启动的时候会非常耗时。Secondary NameNode的作用非常简单,就是按照配置的条件:时间,或者用户对HDFS的操作数到达指定的阈值时,从NameNode那里获取images、文件,和edits文件。并将edits文件里的操作写入images文件。下次NameNode重启就可以从Scondary NameNode那里获取合并过的images文件。加快启动速度。如果NameNode失效,我们也可以从Scondary NameNode那里拿到一个images文件的备份。但是这个备份肯定不是最新的。因为在上次将edits文件里的操作合并进images后,最新生成的edits文件并没有被Secondary NameNode合并进images文件。

Checkpoint Node

CheckPoint Node 和Secondary NameNode的功能一样,并且多了一个功能就是将合并后的images文件上传到NameNode上。

Backup Node

Backup Node和CheckPoint Node的功能一样,但是它不需要定期从NameNode下载edits文件,NameNode在进行一个对HDFS的操作时,并且会把这个操作也发给Backup Node。 Backup Node会在内存里维护一个HDFS 实时的文件目录结构。和CheckPoint Node相比,它永远都是最新的HDFS目录文件结构。HDFS里只能定义一个Backup Node,而且也没必要再定义CheckPoint node了。一旦运行了Backup Node, NameNode就可以通过配置不在本地保存images和edits文件了。这样就减轻了NameNode的负担。

NameNode的高可用

上边说到的几种通过对NameNode里images和eides文件的备份来达到对HDFS内文件系统备份。但是它们都不能做到高可用,就是NameNode一旦失效还是需要人根据images文件手工恢复。关于NameNode的高可用我们后边专门用一篇文章来讲。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

%d 博主赞过: