Hadoop源碼學習筆記(2)--Hdfs的啟動流程分析

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 、 DataNodeSecondaryNameNode 、 JournalNode。

hdfs也是一個shell文件,通過文本應用打開后,我們看到在該文件的執行邏輯如下:

hdfs執行邏輯

節點類型和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進行分析,啟動流程如下:

NameNode

如圖所示,對于REGULAR模式而言,NameNode節點主要啟動了下面三個組件:

NameNode

NameNodeHttpServer

startHttpServer 會啟動一個 NameNodeHttpServer。

NameNodeHttpServer 是一個基于 jetty 服務器的簡單封裝,提供給使用人員一個簡單的節點狀態查詢頁面,默認的綁定端口是 :9870,靜態頁面代碼路徑是 webapps/namenode,這一部分由于不涉及到核心邏輯,不做介紹。

FSNamesystem

loadNamesystem 會構建一個 FSNamesystem 對象,FSNamesystemNameNode 中最核心的一個模塊,負責處理維護整個分布式文件系統。詳細的處理邏輯會在后續的章節做仔細介紹。

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 , lifelineRpcServerclientRpcServer 三種 RPC.Server。

DataNode 啟動邏輯

DataNode 在整個hdfs框架中負責具體的文件存儲。

我們知道DataNode的啟動類是org.apache.hadoop.hdfs.server.datanode.DataNode

DataNode啟動邏輯

他的啟動邏輯如上圖所示。和NameNode類似,在DataNode中同樣啟動了一個基于 jetty Server的 HTTP 服務器,負責向使用人員展示節點狀態;同樣還有一個基于 RPC.Server 的 socket 鏈接負責 hdfs集群 的內部通信。

DataNode

DataXceiverServer

initDataXceiver 會啟動一個 DataXceiverServer 類。

DataXceiverServer 負責接收通過TCP協議傳輸過來的文件數據,會在下一章介紹 hdfs 的文件傳輸的時候做介紹,這里先略過

DatanodeHttpServer

DatanodeHttpServerNameNodeHttpServer 一樣,也是一個基于 jetty 服務器的封裝,負責向使用人員提供當前Datanode的節點狀態信息,默認的啟動端口是 :9864,靜態頁面代碼路徑 webapps/datanode,同樣這一部分不設計核心邏輯,不做介紹

RPC.Server

DataNode中也存在一個RPC.Server對象,負責維持節點間通信,在下一篇文章中會做詳細介紹。

BlockPoolManager

由于在hdfs中文件路徑和文件內容是相互隔離的,在DataNode負責存放分布式的文件內容,但是對于DataNode自身并不知道自己的文件名,只有一個唯一的 blockId 用以定位文件信息。

BlockPoolManager 中,DataNode會定期上報當前節點的 blockId 列表,以便告知NameNode節點中擁有的文件內容。具體的邏輯會在 hdfs的文件傳輸的時候做介紹。

總結

在本文中,沒有過多的對源碼進行分析,只簡單的介紹了 NameNodeDataNode 兩個節點的啟動邏輯。

原因很簡單,每個子組件的內容都需要結合 NameNodeDataNode 甚至還需要 Client 三者結合來講解。而且每個子組件的邏輯也會比較復雜,已經無法放在一個小節里進行講述。

所以,本文中只有 start-dfs.sh 的啟動邏輯和 NameNodeDataNode 的關鍵組件構成。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容