Hdfs 的基础架构
Hdfs基础架构如上图所示。 默认情况下,Hdfs
由一个 Namenode
和多个 DataNode
组成。
hdfs
作为一个分布式文件存储系统,他的文件路径和文件内容是相互隔离的。 文件路径信息保存在 NameNode
中,文件内容则分布式的保存在 DataNode
中。
也就是说对于一个大文件,它可能被根据其文件大小切割成多个小文件进行存储,同时这些小文件可能被分布式的存储在不同的DataNode
中。
当Client希望获取这个文件时,则需要先根据文件路径从 NameNode
中获取他对应的区块在不同的 DataNode
中的信息,然后才能够从 DataNode
中取出数据,还原成一个大文件。
具体的代码逻辑会在之后的读写操作中介绍,这里我们先看看 hdfs 集群的启动流程。
Hdfs 集群启动流程
默认情况下,我们通过 ${HADOOP_HOME}/sbin/start-dfs.sh
启动整个 Hdfs
集群。
hdfs namenode "${HADOOP_HDFS_HOME}/bin/hdfs" --workers --config "${HADOOP_CONF_DIR}" --hostnames "${NAMENODES}" --daemon start namenode ${nameStartOpt}
hdfs datanode "${HADOOP_HDFS_HOME}/bin/hdfs" --workers --config "${HADOOP_CONF_DIR}" --daemon start datanode ${dataStartOpt}
hdfs secondarynamenode "${HADOOP_HDFS_HOME}/bin/hdfs" --workers --config "${HADOOP_CONF_DIR}" --hostnames "${SECONDARY_NAMENODES}" --daemon start secondarynamenode
hdfs journalnode "${HADOOP_HDFS_HOME}/bin/hdfs" --workers --config "${HADOOP_CONF_DIR}" --hostnames "${JOURNAL_NODES}" --daemon start journalnode
hdfs zkfc "${HADOOP_HDFS_HOME}/bin/hdfs" --workers --config "${HADOOP_CONF_DIR}" --hostnames "${NAMENODES}" --daemon start zkfc
在 start-dfs.sh
文件中,我们看到shell文件通过执行hdfs
命令先后启动 NameNode
、 DataNode
、 SecondaryNameNode
、 JournalNode
。
hdfs
也是一个shell文件,通过文本应用打开后,我们看到在该文件的执行逻辑如下:
节点类型和Java类的一一对应
在hdfs
文件中可以看到,传入的第一个参数对应着需要启动节点的类型,使用 hdfscmd_case
根据节点类型可以找到对应需要执行的Java类,节点对应表如下。
节点类型 | Java类 |
---|---|
namenode | org.apache.hadoop.hdfs.server.namenode.NameNode |
datanode | org.apache.hadoop.hdfs.server.datanode.DataNode |
secondarynamenode | org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode |
journalnode | org.apache.hadoop.hdfs.qjournal.server.JournalNode |
Tips:类似datanode根据是否是secure mode会有多个Java类对应,但这里只列出最常用的类
为远程机器启动hdfs
通过解析节点类型,hdfs
找到了对应的Java类。接下来就应该是启动并执行这个Java类。
但是如果在启动命令中包含了 --worker
参数,就代表着需要链接到其他节点机器上执行命令。在处理传参的时候,发现--worker
后,会将 ${HADOOP_WORKER_MODE}
设置为 true, 从而执行 hadoop_common_worker_mode_execute
(对应的方法逻辑在 hadoop-functions.sh
文件中)。在 hadoop_common_worker_mode_execute
中,通过读取配置文件信息,获取到真实运行设备的hostname
,通过ssh
执行一个不带--worker
选项的hdfs
命令,使得hostname
对应的节点机器能够启动hdfs
节点。
注意:如果需要通过这种方法启动远程机器,需要将启动机器的.ssh
公钥加入被启动机器的信任列表中: cat target/id_rsa.pub >> ~/.ssh/authorized_keys
,否则无法直接链接上对应设备
本地启动hdfs
我们通过ssh
让远程设备启动hdfs节点时,会传递过去一个不带--worker
的可执行命令。
因此通过hdfs
启动节点时,运行逻辑和之前保持一致,只是${HADOOP_WORKER_MODE}
不为true
。此时通过判断是否需要在后台执行命令,我们分别通过 hadoop_daemon_handler
或者 hadoop_java_exec
在前台或后台启动对应的Java任务。
这里需要留意的是,在通过 hdfscmd_case
解析节点指令时,或默认将 ${HADOOP_DAEMON_MODE}
设置为 true
,使得各个节点默认在后台运行。
NameNode 启动逻辑
NameNode
在整个hdfs
中扮演着一个很重要的角色,他负责整个文件系统的路径和数据的管理工作,比较类似 Unix 系统中的 inode table。
Client 通过 NameNode
获取到指定路径的分布式文件的 metadata,找到存放在 DataNode
的数据位置,就像从 inode talbe中获取 inode 编号,然后才能去访问具体的分布式文件。
从上一小节的表格中,我们看到 NameNode 对应的启动类是 org.apache.hadoop.hdfs.server.namenode.NameNode
,接下来我们通过走读NameNode::main
具体查看节点的启动流程。
由于 NameNode
的启动参数很多,类似 FORMAT
,CLUSTERID
,IMPORT
等等启动参数并不会被用来启动 NameNode
。为了简单起见,这里只针对默认启动逻辑 REGULAR
进行分析,启动流程如下:
如图所示,对于REGULAR
模式而言,NameNode
节点主要启动了下面三个组件:
NameNodeHttpServer
startHttpServer
会启动一个 NameNodeHttpServer
。
NameNodeHttpServer
是一个基于 jetty 服务器的简单封装,提供给使用人员一个简单的节点状态查询页面,默认的绑定端口是 :9870
,静态页面代码路径是 webapps/namenode
,这一部分由于不涉及到核心逻辑,不做介绍。
FSNamesystem
loadNamesystem
会构建一个 FSNamesystem
对象,FSNamesystem
是 NameNode
中最核心的一个模块,负责处理维护整个分布式文件系统。详细的处理逻辑会在后续的章节做仔细介绍。
RPC.Server
createRPCServer
会启动一个 RPC.Server
线程。
RPC.Server
负责处理 hdfs 集群中的内部通信,在 RPC.Server 中绑定了一个 socket 端口,利用protobuf
的序列化框架进行数据传输,关于 RPC.Server 的交互逻辑会在下一章中做详细介绍,这里可以简单理解为一个使用socket通信的rpc访问框架。
if (serviceRpcAddr != null) {
serviceRpcServer = new RPC.Builder(conf).build();
}
if (lifelineRpcAddr != null) {
lifelineRpcServer = new RPC.Builder(conf).build();
}
clientRpcServer = new RPC.Builder(conf).build()
在NameNodeRpcServer
的构造方法中可能会构造 serviceRpcServer
, lifelineRpcServer
和 clientRpcServer
三种 RPC.Server
。
DataNode 启动逻辑
DataNode
在整个hdfs
框架中负责具体的文件存储。
我们知道DataNode
的启动类是org.apache.hadoop.hdfs.server.datanode.DataNode
他的启动逻辑如上图所示。和NameNode
类似,在DataNode
中同样启动了一个基于 jetty Server的 HTTP 服务器,负责向使用人员展示节点状态;同样还有一个基于 RPC.Server 的 socket 链接负责 hdfs集群 的内部通信。
DataXceiverServer
initDataXceiver
会启动一个 DataXceiverServer
类。
DataXceiverServer
负责接收通过TCP协议传输过来的文件数据,会在下一章介绍 hdfs 的文件传输的时候做介绍,这里先略过
DatanodeHttpServer
DatanodeHttpServer
和 NameNodeHttpServer
一样,也是一个基于 jetty 服务器的封装,负责向使用人员提供当前Datanode
的节点状态信息,默认的启动端口是 :9864
,静态页面代码路径 webapps/datanode
,同样这一部分不设计核心逻辑,不做介绍
RPC.Server
DataNode
中也存在一个RPC.Server
对象,负责维持节点间通信,在下一篇文章中会做详细介绍。
BlockPoolManager
由于在hdfs
中文件路径和文件内容是相互隔离的,在DataNode
负责存放分布式的文件内容,但是对于DataNode
自身并不知道自己的文件名,只有一个唯一的 blockId
用以定位文件信息。
在 BlockPoolManager
中,DataNode
会定期上报当前节点的 blockId
列表,以便告知NameNode
节点中拥有的文件内容。具体的逻辑会在 hdfs的文件传输的时候做介绍。
总结
在本文中,没有过多的对源码进行分析,只简单的介绍了 NameNode
和 DataNode
两个节点的启动逻辑。
原因很简单,每个子组件的内容都需要结合 NameNode
和 DataNode
甚至还需要 Client
三者结合来讲解。而且每个子组件的逻辑也会比较复杂,已经无法放在一个小节里进行讲述。
所以,本文中只有 start-dfs.sh
的启动逻辑和 NameNode
与 DataNode
的关键组件构成。
网友评论