Hadoop分布式文件系统(HDFS)是Hadoop生态系统的核心组件之一,它是一个可扩展的分布式文件系统,用于存储大量数据。本文将对HDFS的源代码进行解析,以便更好地理解其工作原理。

HDFS的核心组件

HDFS由三个核心组件组成:NameNode,DataNode和客户端。NameNode是HDFS的主节点,负责管理文件系统的命名空间和客户端的元数据。DataNode是HDFS的从节点,负责存储实际的数据块。客户端是与HDFS交互的用户程序,它们可以读取或写入数据。

NameNode启动流程

1.1 NameNode1.2 启动流程main方法

startHttpServer 启动HTTPServer loadNamesystem 加载元数据 todo

从磁盘上加载FSFSImage到内存中合并元数据JournalSet的成员变量journals List根据配置读取到NameNode的路径本地和JournalNode路径远程,生成FileJournalnodeManager和QuorumJournalManagerFsimage合并后写入到磁盘上打开editLog开始写日志,初始化两个流用于写入日志使用 QuorumJournalManager-》QuorumOutputStream FileJournalManager -》 EditLogFileOutputStream createRpcServer

创建ServiceRPCServer创建ClientRpcServer startCommonServices 公共服务启动

检查是否有足够的磁盘存储元数据

通过扫描core-site.xml hdfs-site.xml知道哪些磁盘用于存储元数据遍历磁盘如果磁盘空间小于100M就返回false 安全模式检查

如果datanode累计汇报的block的数目小于0.999(默认)*总的block个数,进入安全模式如果存活的datanode小于某个阈值的时候也会进入安全模式且阈值不等于零,进入安全模式,默认阈值为零存放元数据的空间是否大于100M如果不大于100M也会进入安全模式 启动管理心跳的服务 HeartbeatManager的一个监听心跳的一个成员变量线程,并启动这个线程,跳转到3 如果是NameNode(Secondry)还会启动EditLogTailer线程从Journalnode上同步元数据,启动StandbyCheckpointer用于检测NameNode的EditLog和FsImage的数据是否需要合并

DateNode启动流程

2.1 DateNode 2.2 启动流程main方法

createDataNodeinitDataXceiver

实例化 DataXceiverServer 线程用于DataNode用来接收客户端和其他DataNode传过来数据的服务 startInfoServer 启动http服务initIpcServer 启动RPC服务创建了BlockPoolManager

一个联邦只有一个BlackPool,对应一个BPOfferService一个联邦一般有两个NameNode(avtive和standBy)会启动两个BPServiceActor线程用于DataNode向NameNode(一个是NameNode active 一个是NameNode standBy)进行注册 2.3 向NameNode进行注册

首先获取到NameNode的代理,校验NameSpace、clusterId、BlockPoolId的信息。创建注册信息,通过NameNode的NameNodeRpcServer的registerDatanode向NameNode进行注册通过NameNodeRpcServer的FSNamesystem成员变量获取DataNodeManager往DataNodeManager的各种内存结构里面添加各种信息把注册上来的DataNode加入到HeartbeatManager中用于心跳管理 2.4 向NameNode发送心跳

每隔3秒钟通过NameNodeRpcServer服务向NameNode进行注册,从DataNodeManager中获取注册DataNode的注册信息,主要更改心跳时间,并回调带回来一些NameNode的发送过来的指令。 2.5 启动blockPoolManager、dataXceiverServer、ipcServer守护线程

NameNode和DataNode心跳管理

NameNode启动公共服务 startCommonServices的时候会启动一个HeartbeatMananger的的线程服务用来检查DataNode的心跳信息,判断是否死去,查看HeartbeatManger的run方法。每隔30s或者五分钟执行一次心态检查,如果10分三十秒还没有检测到心跳,那么就将这个DataNode设置为死亡状态,从DatanodeManager里面将各种DataNode各种注册信息移除掉。 元数据管理流程

场景驱动FileTest类创建目录DistributedFileSystem mkdirs 调用RpcNameNodeServer mkdirs首先更新NameNode 的内存中的目录树结构创建日志对象,并将日志对象记录

将数据先写入到内存的缓冲区中,交换内存的缓冲数据,将数据写入到NameNode的本地磁盘中。将数据先写入到内存的缓冲区中,交换内存的缓冲数据,同时将数据发送到journalNode异步获取到每一个journalNode的JournalNodeRpcServerd的journal方法,通过rpc服务将数据写入到journalNode的本地磁盘中 SeconderyNameNode的EditLogTailer线程会同步Journal的元数据到StandByNameNode上面去

当SeconderyNameNode启动后就会启动EditLogTailer线程从JournalNode来同步元数据到StandByNameNode上首先加载当前自己的元数据日志,并获取当前的元数据日志的最后一条日志的事务ID,通过Http请求去JournalNode上读取日志,并将获取到的元数据作用到自己的内存的元数据目录树里面里面 SeconderyNameNode的StandByCheckPointer线程的checkpoint (EditLogTailerh和StandByCheckPointer都是NameNode启动的时候会启动),StandByNameNode会往NameNodeHttpServer的imagetransfer(ImageServlet的put方法)发送元数据

SeconderyNameNode启动的时候会启动一个StandByCheckPointer线程每隔60秒检验是否需要Checkpoint先获取到当前的最新的日志的事务Id,然后获取到上一次CheckPoint的事务Id,两者相减如果大于等于100万条就需要做checkpoint获取到当前时间和上一次CheckPonit的时间,两者相减如果>=1个小时没有做CheckPoint,那么就需要做一次checkpoint如果满足CheckPoint的其中一个条件,就开始做CheckPoint.

开启一个线程将SeconderyNameNode的元数据持久化到磁盘上面开启一个异步的线程将SeconderyNameNode,通过Http请求的put方式将数据发送到activeNameNode的imagetransfer这个路由上面activeNameNode的ImageServlet的doPut方法不断获取到输入流,保存文件到本地,并将fsimage_N.ckpt重命名为fsimage_N这个文件 HDFS写数据流程

5.1 场景驱动FileTest类写数据 的create()DFSOutputStream.newStreamForCreate首先客户端获取到NameNodeRpcServer的create的方法

调用RpcNameNodeServer服务往NameNode的文件目录树添加INodeFile,并将元数据写入本地磁盘和JournalNode中NameNode leaseManger.addLease()添加契约 将数据放入到一个可排序(按照时间倒叙)的数据结构中,并添加契约的时间。NameNode启动的时候会启动一个LeaseManager的监听线程,每隔两秒钟就会从可排序的数据结构中,拿出第一个契约,如果第一个契约没有过期就直接return,否则再看后续的契约是否过期。如果有过期的数据就从各种数据结构中移除数据。 客户端DFSOutputStream创建并启动DataStreamer线程是写数据的重要对象

当开始启动DataStreamer线程的时候,由于dataQueue里面没有数据会阻塞住线程,只有客户端调用write方法真正开始写数据的时候,该线程才会继续运行当队列中有了数据DataStreamer就会被唤醒并运行

首先向NameNode申请Block

调用NameNodeRpcServer选择存放Block的DataNode目标主机数组修改内存里面的目录树信息,将block信息记录到内存的目录树中并将元数据写入到磁盘中 客户端通过Socket请求连接到第一个DataNode的目标主机,创建输出流启动一个ResponseProcessor线程来监听发送的状态,读取下游的结果,如果发送成功就把ackQueue里面的packet移除。从dataQueue把要发送的这个packet移除出去,然后往ackQueue里面添加这个packet通过输出流把数据写出去写数据异常

把ackQueue的数据写入到dataQueue,清空ackQueue队列重新建立数据管道

如果有一半以上的都有问题,重新构建新的数据管道如果只有一个出问题,就将剩余的重新构建数据管道,然后同步数据即可,后面NameNode会检测到DataNode少了副本就会通知DataNode处理当管道建立成功之后就重新开始写数据 beginFileLease()

客户端开启一个线程每隔一秒钟检查一次,如果超过三十秒没有续约,那么就调用NameNodeRpcServer续约契约的更新时间,移除老的数据结构,更新契约时间,将新的数据放入到数据结构里面。LeaseManager有个线程移除老的契约时间。 5.2 FileTest 写数据 的write()方法

DFSOutputStream父类的write方法写入数据,最终调用DFSOutputStream的父方法FSOutputSummer的write方法HDFS文件 -》 Block文件块(128M) -》 2048 * packet(64K) = 127 * chunk -> chunk 512byte + chunksum 4byte = 516开始以一个chunk的开始写,当写满一个packet或者写满一个Block,就会往dataQueue里面添加packte,然后唤醒DataStreamer的run方法,

如果没有写满的话,等到DataStreamer过了超时时间也会从dataQueue取数据,没有写满一个packet,会利用已有的数据创建一个packet来发送数据 当datanode获取到DataStreamer发送过来的数据后

每发送过来一个请求DataXceiverServer线程都会启动DataXceiver线程用于处理数据。根据不同的请求的操作类型,我们这边是写数据,那么会启动BlockReceive线程,通过socket继续连接下游的datanode,建立通道启动PacketResponder和 ResponseProcessor线程功能类似,是用于判断下游是否写数据成功,成功移除ackQueue

获取当前节点是否已经写入成功获取下游节点的处理结果往上游发送处理结果获取到下游的处理结果,如果处理成功,就从当前的datanode节点的ackQueue队列中移除packet. 不断的接受数据

把packet写入到datanode的ackqueue队列中通过上面连接的数据通道把当前的packet发送的下游的datanode节点校验数据并将数据写入到本地。 往上游写回相应结果

NameNode源代码总结

NameNode是HDFS的核心组件之一,它负责管理文件系统的命名空间和客户端的元数据。以下是NameNode源代码的主要组成部分:

FsNamesystem:这是NameNode的核心组件之一,它负责管理文件系统的命名空间和客户端的元数据。它包含了文件系统的目录树和文件元数据,如文件大小、创建时间、修改时间等。 FSImage:这是文件系统镜像的核心组件,它是文件系统的元数据的持久化存储。它将文件系统的元数据保存在本地磁盘上,以便在NameNode重新启动时恢复文件系统的状态。 EditLog:这是文件系统编辑日志的核心组件,它记录了文件系统的所有修改操作。它将修改操作写入本地磁盘,以便在NameNode重新启动时重新应用这些操作。 NameNodeRpcServer:这是NameNode的RPC服务器,它处理客户端和DataNode之间的通信。它提供了一组RPC接口,用于管理文件系统的命名空间和元数据。

DataNod总结

DataNode是HDFS的从节点,它负责存储实际的数据块。以下是DataNode源代码的主要组成部分:

FsDatasetImpl:这是DataNode的核心组件之一,它负责存储实际的数据块。它包含了文件系统的数据块和元数据,如块大小、创建时间、修改时间等。 DataNodeRpcServer:这是DataNode的RPC服务器,它处理客户端和NameNode之间的通信。它提供了一组RPC接口,用于管理数据块和元数据。 BlockReceiver:这是DataNode接收数据块的核心组件。它负责接收数据块并将其写入本地磁盘。

客户端源代码总结

客户端是与HDFS交互的用户程序,它们可以读取或写入数据。以下是客户端源代码的主要组成部分:

DistributedFileSystem:这是客户端的核心组件之一,它提供了一组API,用于读取或写入数据。它将API调用转换为RPC请求,并将请求发送到NameNode或DataNode。 DFSClient:这是客户端的核心组件之一,它负责与NameNode和DataNode之间的通信。它将API调用转换为RPC请求,并将请求发送到NameNode或DataNode。

总结

本文对HDFS的源代码进行了简要的解析,以便更好地理解其工作原理。HDFS的核心组件包括NameNode、DataNode和客户端,它们分别负责管理文件系统的命名空间和元数据、存储实际的数据块以及与HDFS交互。HDFS的源代码是Hadoop生态系统的核心组件之一,它为存储大量数据提供了可扩展的分布式文件系统。

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: