HDFS的工作原理是怎么样的?是如何实现HA模式?

原文链接:http://www.ibearzmblog.com/#/technology/info?id=714dcb3957e29185493239b269a9ef65

前言

HDFS是能够提供一个分布式文件存储的系统,在大型数据文件的存储中,能够提供高吞吐量的数据访问,那么它是如何实现数据文件的读写的呢?作为集群老大的NameNode当出现服务不可用的情况,HDFS又如何启用备用节点来实现HA的呢?今天我们来好好说下。
HDFS的工作原理是怎么样的?是如何实现HA模式?_第1张图片

HDFS的读写流程

在讲述读写流程前,还是很有必要重新复述下数据块这个概念,在分布式文件系统中,一个大型数据文件会被切分成多个部分,并分别存储在多个DataNode上,每个文件部分就是一个数据块,数据块存储在DataNode上后,对应的DataNode就会将块的信息报告给NameNode。

讲完这些,我们开始说如何读写。

如何读

看下面流程图:
HDFS的工作原理是怎么样的?是如何实现HA模式?_第2张图片
可以看到,要读取HDFS中的文件一共分为6个步骤:

  1. 当HDFS客户端需要读取一个数据文件的时候,首先会调用FileSystem的open()方法获取一个dfs对象(DistributedFileSystem)
  2. DFS通过RPC从NameNnode中获取文件第一批块的位置信息后,会返回一个FsDataInputStream对象。
  3. 返回的FsDataInputStream会被封装成DFSInputStream(分布式文件系统输入流),里面提供了管理NameNode和DataNode输入流的方法。当客户端调用read()方法的时候,DFSInputStream就会找出离客户端最近的DataNode并连接。
  4. 找出DataNode后就会开始读取对应的数据块,数据开始流向客户端。
  5. 当第一个块读取完成后,就会关闭第一个块指向的DataNode连接,然后接着读下一个块。
  6. 当第一批块读取完成后,就会向NameNode获取下一批块的位置信息,然后继续读取。
  7. 当所有块都读取完成后,就会关闭所有的流。

当然,在实际情况下,想一直那么顺利的传输数据是不可能的,如果在读取数据的时候,DataNode和DFSInputStream发生异常的时候,那么DFSInputStream会尝试获取当前读取块第二近的DataNode节点,并会记录哪个DataNode发生错误,后面涉及到该出事DataNode读取的时候,就会自动跳过。

如果读取的块已经坏了,那么就会将这种情况汇报给NameNode,并且从其他DataNode读取该块数据。

如何写

看下面流程图:
HDFS的工作原理是怎么样的?是如何实现HA模式?_第3张图片

  1. 和读操作一样,首先通过FileSystem获取一个DFS对象,并通过DFS对象来的create()方法来创建一个新的文件。
  2. DFS通过RPC调用NameNode去创建一个新文件,NameNode在创建前会做一些额外的校验,如文件是否已经存在、客户端是否有权限创建文件等等。
  3. 前面的操作完成后,DFS会返回一个FsDataOutputStream对象,同样,FsDataOutputStream会被封装成DFSOutputStream(分布式文件系统输入流),同样,DFSOutputStream也提供了协调DataNode和NodeNode的方法。
  4. 当客户端开始写数据的时候,就会将数据块切分成一个个数据包,然后将这些数据包排成一条数据队列。
  5. 多个DataNode组成一条数据管道,当开始传输的时候,首先第一个数据包会传到数据管道的第一个DataNode,当第一个DataNode收到后会将这个数据包传给下一个DataNode。
  6. DFSOutputStream除了数据管道外,还维护着另一个队列:响应队列,这个队列也是由数据包组成的,当DataNode收到数据块的数据包后,就会返回一个响应数据包,当管道中所有的DataNode都收到响应数据包的时候,响应队列才把对应的数据包移除
  7. 客户端在写操作完成后,就会调用close()关闭输出流。
  8. 同时,客户端会通知NameNode把文件标记为已完成,然后NameNode会把文件写入成功的结果返回给客户端。这时整个写操作才完成。

当然,凡是涉及到节点之前的通信,都大概率会出现一些奇怪的问题,例如网络不可用啊、通信节点掉线啊等等,对于这种情况,写操作要比读操作要复杂一点,如果在写操作过程中其中一个DataNode发生错误,那么就有下面几个步骤来处理:

  1. 管道关闭
  2. 正常的DataNode正在写的块会由一个新的ID,并且这个ID会汇报给NameNode,而失败的DataNode上发生错误的块就会在下次上报心跳的时候删掉。
  3. 失败的DataNode会被从管道中移除,而块中剩下的数据包会继续写入到管道里其他的DataNode上。
  4. NameNode同时会标记这个块的副本数量少于指定值,那么会在后面将这个块的副本在其他DataNode上创建。

HDFS的高可用实现

讲完了HDFS的读写流程,我们接下来说下HDFS如何实现高可用。

HDFS的NameNode为单一节点,为HDFS提供对外统一服务,这说明如果NameNode因为某些原因掉线了,那整个HDFS集群就会瘫痪。为了防止这种情况在生产环境中出现,就引入了高可用(HA)模式。

在HA模式中,一般由两个NameNode组成,一个是处于激活(Active)状态,另一个就处于待命(Standby)状态,处于激活状态的NameNode对外提供统一服务,而待命状态的NameNode则不对外提供服务,同时及时同步激活状态的NameNode。当激活的NameNode掉线了,待命的NameNode就马上切换状态,变成Active。

HDFS的高可用架构图如下所示:
HDFS的工作原理是怎么样的?是如何实现HA模式?_第4张图片

在这个架构中出现了一些从没见过的组件,下面我来逐个剖析:

  • NameNode的Active和Standby状态上面说了,这里就不细说。
  • 主备切换器,它是另外一个单独的进程运行,主要负责NameNode的主备切换。主备切换器实时健康NameNode的情况,当NameNode发送故障时,就会通过Zookeeper的选举机制来进行选举和切换。
  • JournalNode集群:这是一个共享数据存储系统,这个系统保存了NameNode在运行过程中产生的HDFS元数据,而备用的NameNode节点则会从通过JournalNode来同步主NameNode的信息。当新的主NameNode确认元数据完全同步后才会对外提供服务。

结尾

HDFS的工作原理已经讲到这里,后面会更新YARN方面的文章。

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