Yarn源碼分析之集羣啓動流程


本文以hadoop2.7.1的源碼分析(主要是最新版本考慮更多因素,源碼不夠純粹)

集羣啓動腳本分析

首先我們從啓動hadoop集羣說起,我們一般在單點hadoop啓動集羣一般直接使用 sbin/start-all.shsbin/stop-all.sh ,我們直接看啓動腳本:

bin=`dirname "${BASH_SOURCE-$0}"`
bin=`cd "$bin"; pwd`

DEFAULT_LIBEXEC_DIR="$bin"/../libexec
HADOOP_LIBEXEC_DIR=${HADOOP_LIBEXEC_DIR:-$DEFAULT_LIBEXEC_DIR}
. $HADOOP_LIBEXEC_DIR/hadoop-config.sh

# start hdfs daemons if hdfs is present
if [ -f "${HADOOP_HDFS_HOME}"/sbin/start-dfs.sh ]; then
  "${HADOOP_HDFS_HOME}"/sbin/start-dfs.sh --config $HADOOP_CONF_DIR
fi

# start yarn daemons if yarn is present
if [ -f "${HADOOP_YARN_HOME}"/sbin/start-yarn.sh ]; then
  "${HADOOP_YARN_HOME}"/sbin/start-yarn.sh --config $HADOOP_CONF_DIR
fi

可以看出先後執行啓動了 hadoop-config.shstart-dfs.shstart-yarn.sh 。由於本文主要探討Yarn啓動過程,所以我們直接看 start-yarn.sh

echo "starting yarn daemons"

bin=`dirname "${BASH_SOURCE-$0}"`
bin=`cd "$bin"; pwd`

DEFAULT_LIBEXEC_DIR="$bin"/../libexec
HADOOP_LIBEXEC_DIR=${HADOOP_LIBEXEC_DIR:-$DEFAULT_LIBEXEC_DIR}
. $HADOOP_LIBEXEC_DIR/yarn-config.sh

# start resourceManager
"$bin"/yarn-daemon.sh --config $YARN_CONF_DIR start resourcemanager
# start nodeManager
"$bin"/yarn-daemons.sh --config $YARN_CONF_DIR start nodemanager
# start proxyserver
#"$bin"/yarn-daemon.sh --config $YARN_CONF_DIR start proxyserver

可以看出Yarn先後調用 yarn-daemon.sh 啓動 resourcemanager 組件;調用 yarn-daemons.sh 啓動 nodemanager 組件,只不過 yarn-daemons.sh 也會調用 slaves.sh 後同樣也會調用 yarn-daemon.sh ,所以我們繼續分析 yarn-daemon.sh 腳本,我們看關鍵代碼(如需看完整代碼,點鏈接查閱即可):

...
  echo starting $command, logging to $log
    cd "$HADOOP_YARN_HOME"
    nohup nice -n $YARN_NICENESS "$HADOOP_YARN_HOME"/bin/yarn --config $YARN_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &
    echo $! > $pid
...

可以看出最終調用 yarn 腳本,由於代碼比較多,我們直接看啓動 resourcemanagernodemanager 組件的代碼部分:
在這裏插入圖片描述
從腳本可以看出,會分別調用 org.apache.hadoop.yarn.server.resourcemanager.ResourceManagerorg.apache.hadoop.yarn.server.nodemanager.NodeManager 類,調用 exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $YARN_OPTS -classpath "$CLASSPATH" $CLASS "$@" 啓動JVM進程啓動常駐服務,即 ResourceManagerNodeManager 是入口類,我們以 ResourceManager 組件,繼續往下分析…

注:上面介紹的一般在單節點上啓動,但是在分佈式情況,ResourceManager和NodeManager等分佈在不同機器上,啓動的進程不相同,
因此 推薦在不同節點分別啓動組件 ,可以參考:

  • sbin/hadoop-daemons.sh start namenode 單獨啓動NameNode守護進程
  • sbin/hadoop-daemons.sh start datanode 單獨啓動DataNode守護進程
  • sbin/hadoop-daemons.sh start secondarynamenode 單獨啓動SecondaryNameNode守護進程
  • sbin/yarn-daemon.sh start resourcemanager 單獨啓動ResourceManager守護進程
  • sbin/yarn-daemon.sh start nodemanager 單獨啓動NodeManager守護進程

ResourceManager啓動流程

首先我們先看下ResourceManager中的功能模塊,有利於宏觀掌握。ResourceManager在底層代碼實現上將各個功能模塊分的比較細,各個模塊功能具有很強的獨立性。如下圖:
在這裏插入圖片描述
從上面啓動腳本可以看出, org.apache.hadoop.yarn.server.resourcemanager.ResourceManager 是入口類的 main函數。
在這裏插入圖片描述
其中重點需要分析的就是上面中的 resourceManager.init(conf);resourceManager.start(); ,下面分別介紹

初始化流程

如上面的代碼中的 resourceManager.init(conf); ,首先調用父類 AbstractServiceinit 函數
在這裏插入圖片描述
從代碼,可以其服務初始化實現在 ResourceManager 類的 serviceInit 函數,如下
在這裏插入圖片描述

setupDispatcher() 設置的是 Always On 服務,即不考慮HA狀態的一直運行的服務。其初始化的 AsyncDispatcher 內部是 有一個 阻塞的事件隊列,有一個一直運行的執行線程,當阻塞隊列中有事件被放入,執行線程會把事件取出來,並獲取事件的類型,從事件註冊器 Map<Class<? extends Enum>, EventHandler> 中獲取到對應的 EventHandler 對象,並調用該對象的 dispatch 方法分發事件。這樣就完成了一次異步事件調用。
createAndInitActiveServices();設置的是活動的服務上下文,即需要運行在Active RM節點上的服務,由於本文不重點解析,僅列出啓動服務供參考:

  • RMSecretManagerService
  • ContainerAllocationExpirer
  • AMLivelinessMonitor
  • RMNodeLabelsManager
  • RMStateStore
  • RMApplicationHistoryWriter
  • SystemMetricsPublisher
  • NodesListManager
  • ResourceScheduler
  • SchedulerEventDispatcher
  • NMLivelinessMonitor
  • ResourceTrackerService
  • ApplicationMasterService
  • ClientRMService
  • ApplicationMasterLauncher
  • DelegationTokenRenewer

至此,配置加載和子服務初始化工作分析完了,下面我們分析,RM的啓動流程

啓動流程

我們回到ResourceManager類的 resourceManager.start(); 繼續分析,同樣首先調用父類 AbstractServicestart 函數
在這裏插入圖片描述
從代碼,可以其服務初始化實現在 ResourceManager 類的 serviceStart 函數,如下
在這裏插入圖片描述
繼續調用父類 CompositeServiceserviceStart 函數
在這裏插入圖片描述
循環啓動之前啓動的每個服務。
自此整個Yarn的啓動過程就分析完了…

中央事件調度器-AsyncDispatcher

由於AsyncDispatcher作爲Yarn的一個重要的啓動常駐服務,所以我們在此分析一下。
我們都知道,Yarn是採用了基於事件驅動的併發模型:

  • 所有狀態機都實現了EventHandler接口,很多服務(類名通常帶有Service後綴)也實現了該接口,它們都是事件處理器。
  • 需要異步處理的事件由中央異步調度器(類名通常帶有Dispatcher後綴)統一接收/派發,需要同步處理的事件直接交給相應的事件處理器。

在這裏插入圖片描述

事件調度就是基於 AsyncDispatcher 實現的,由上面代碼分析可得,AsyncDispatcher也是在yarn啓動過程中 resourceManager.init(conf); 做爲服務初始化的一員,最後在 resourceManager.start(); 分別啓動的,因此其啓動最終也是調用 org.apache.hadoop.yarn.event.AsyncDispatcher 的函數 serviceStart 啓動:

在這裏插入圖片描述
從代碼可以看出,其實例化了一個子線程,用於異步處理事件,我們繼續跟進代碼,如下:
在這裏插入圖片描述
可以看出,在線程中循環從阻塞隊列中拿出一個事件,然後分發事件處理,此過程相當於“生產者和消費者模型”中的消費者。而生產者則是由Client通過RPC提交給Yarn後,add到該阻塞隊列,本文不再詳述這部分。
具體的分發原理可以參考:Yarn的事件驅動模型與狀態機

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章