概述

hdfs datanode采用块的方式存放hdfs数据,datanode具有以下特点:

  • datanode会通过心跳维持和namenode的联系,心跳的响应同样会携带namenode的指令信息。
  • 客户端在读写数据的时候,会直接和datanode建立连接完成数据块的读写,并在读写完成之后将相信息汇报给namenode

详解

在介绍datanode详细信息之前,我们有必要对当前的hdfs的整体架构有一个清晰的认识

整体架构

hdfs的架构并不是一成不变的,在2.x的时候hdfs的整体架构就发生了重大的变更,笔者所看的包括业务中使用到的是2.6版本的代码,因此讲解也将会使用 2.x的架构来进行讲解,不过在讲解2.x的架构之前,还是有必要对旧的版本的架构有一个清晰的认知,这样才可以更好的理解现有的架构所带来的好处。

hdfs 2.x之前的架构

如上图所示为hdfs 1.x的逻辑示意图,下面对上面的架构进行简单的描述以下,hdfs从逻辑上可以分为两层(外面大的实线框所示):

  • 命名空间管理层:用于管理整个文件系统的命名空间,管控的对象为文件、目录、文件包含的数据块的信息,对外提供常见的文件系统的操作(主要是针对元数据的管理)
  • 数据块存储管理层:
    • 数据块管理:管理数据节点信息和数据块信息,提供数据块元信息的操作接口
    • 存储管理:管理datanode上数据块的物理存储,提供数据块数据操作的接口 namenode实现了命名空间管理层和数据块管理层,datanode则主要实现了数据块存储管理层中的存储管理层,这样datanode相对来说功能单一,只是提供了数据块数据操作的接口, 并通过心跳将数据块上报到namenode,之后继续执行namenode下发的指令。而namenode实现的功能则几种管理元数据(namespace元数据、数据块元数据)。 这种架构带来的问题也很明显:
  • 所有的元数据都保存在namenode上,当datanode规模达到一定程度之后,namenode用于管理元数据的内存就会被撑爆
  • 所有的数据操作基本都需要和namenode进行交互,因此namenode成为性能的瓶颈
  • 命名空间管理和数据块管理耦合在一起,难以让其他服务单独使用数据块管理的功能(如:hbase)

一言以蔽之,这种架构耦合度比较高,namenode成为整个系统的瓶颈。

hdfs 2.x之后的架构

在前面提到的hdfs的架构中,我们了解到namenode成为整个集群的瓶颈,想要解除这种限制可以的方法就需要能够 水平的扩展namenode(有点类似于一致性hash)。hdfs 2.x提供了联邦(federation)的机制,federation架构中的hdfs 集群可以定义多个namespace,这些namespace分别存放在不同的namenode上,而namenode之间是相互独立的(这又有点像是分段锁的机制)。 书上说datanode会想集群中所有的namenode注册,并周期性的向所有的所有的namenode进行块汇报,此处存疑,如果是这样的话,namenode根本没有水平扩展 datanode同样会通过心跳的机制获取并执行namenode下发的指令信息。 其整体架构如下图所示:

hdfs的联邦机制引入了两个新的概念:

  • blockpool(块池):一个块池由属于同一个命名空间的所有的数据块组成,块池中的数据块可以存放在集群的所有的节点上,因此数据节点上报数据其实是通过datanode上报到所有的namenode,而namenode之间因为是不同的命名空间,因此namenode之间是相互隔离的
  • namespacevolume(命名空间卷):一个namenode管理的命名空间及对应的块池一起被成为命名空间卷

相对于旧的架构federation 所带来的好处也是显而易见的,那就是支持命名空间的扩展,在安全性上面同样也支持命名空间级别的隔离 ,后续想要做租户的管理应该也是可以通过这种方式来实现。(之前一直有一个疑惑,那就是datanode会向所有的namenode进行数据块的汇报,这样 不是会导致集群的规模没办法真正的扩大,这种考虑的方向是把数据节点当作一个整体来进行考虑的,不过真实的情况应该是,考虑数据节点上的数据块, 也就是将数据块作为基本的单位来进行考虑,一个namenode下所支持的数据块的数量是会受到namenode内存大小的限制) 在介绍了整体的架构之后,我们从业务的视角来观察一下datanode的结构。

datanode业务分层

好的业务一定是分层的,分层是为了更好的解耦和逻辑的复用,我们接下来看一下datanode的业务分层,并快速的过一下每一层锁实现的功能,如下所示:

datanode数据层

datanode数据层在我看来和我们后台的持久层并没有什么实质区别,只不过一个是数据库,一个是文件系统而已。 数据层又可以分为两个部分:

  • data storage(存储管理):datanode上包含的数据块会通过块池(blockpoolslicestorage)的方式进行组织,存储管理就是通过数据块的管理实现磁盘的管理
  • fsdataset(文件系统数据集):抽象了datanode上的数据块的管理,要注意datanode上的数据块管理的组织方式和namenode命名空间卷是一致的,datanode会通过fsvolumeimpl来进行管理数据块,而一个fsvolumeimpl就对应了一个命名空间卷。

datanode逻辑层

逻辑层是在数据层的基础之上进行的封装,主要的作用是和namenode进行交互,具体的执行逻辑可以分为:

  • blockpoolmanager:管理所有块池的接口(块池的信息是存放在namenode中的),blockpoolmanager会持有多个bpofferservice来分别对每一个块池进行管理(块池和命名空间卷一一对应),每一个bpofferservice都会持有两个bpofferserviceactor来分别向每一个命名空间卷的active namenode和standby namenode进行管理
  • datablockscanner:周期性的扫描数据块并对数据块进行校验
  • directoryscanner:周期性的通过磁盘上的数据更新内存中的元数据

datanode服务层

是服务层更多的是datanode对外提供的服务,主要分为以下三块

  • httpserver:对外提供http服务用于展示datanode的状态
  • ipcserver:rpc服务端,用来响应client、namenode、datanode的请求
  • dataxceiverserver: 数据传输服务,用于构建datanode和client以及其他的datanode之间的数据流

代码详解

小结