說明:
本文的源碼分析基于hive-0.12.0-cdh5.0.1。
Driver類的主要作用是用來編譯并執行hive指令,然後傳回執行結果。這裡主要分析Driver類的運作邏輯,其時序圖如下:
從時序圖上可以看出有以下步驟:
run方法調用内部方法runInternal
在runInternal方法内部先,調用HiveDriverRunHookContext的preDriverRun方法
調用compileInternal方法
compileInternal方法内部調用compile方法
compile方法内,先調用HiveSemanticAnalyzerHookContext的preAnalyze方法
再進行文法分析,調用BaseSemanticAnalyzer的analyze方法
調用HiveSemanticAnalyzerHookContext的postAnalyze方法
再進行文法校驗,調用BaseSemanticAnalyzer的validate方法
compileInternal方法運作完成之後,調用checkConcurrency方法
再來運作execute方法,該方法用于運作任務
最後,調用HiveDriverRunHookContext的postDriverRun方法
在繼續分析之前,需要弄清楚Driver類初始化時做了什麼事情。
在CliDriver的<code>processCmd(String cmd)</code>方法中可以看到proc是在CommandProcessorFactory類中new出來的并調用了init方法。
CommandProcessorFactory.get方法代碼片段:
init方法和構造方法代碼如下:
從上可以看出僅僅是初始化了conf屬性和重置了Operator的id。
1、調用runInternal方法,根據該方法傳回值判斷是否出錯。
2、runInternal方法内,運作HiveDriverRunHook的前置方法preDriverRun
3、判斷是否需要編譯,如果需要,則運作<code>compileInternal(command)</code>方法,并根據傳回值判斷是否該釋放Hive鎖。hive中可以配置<code>hive.support.concurrency</code>值為true并設定zookeeper的伺服器位址和端口,基于zookeeper實作分布式鎖以支援hive的多并發通路。這部分内容不是本文重點故不做介紹。
<code>compileInternal(command)</code>方法内部代碼說明見下文。
4、判斷是否需要對Task加鎖。如果需要,則調用checkConcurrency方法。
5、調用execute()方法執行任務。
執行計劃開始:<code>plan.setStarted();</code>
先運作ExecuteWithHookContext的前置hook方法,ExecuteWithHookContext類型有三種:前置、運作失敗、後置。
然後建立DriverContext用于維護正在運作的task任務,正在運作的task任務會添加到隊列runnable中去。
其次,在while循環中周遊隊列中的任務,然後啟動任務讓其執行,并且輪訓任務執行結果,如果任務運作完成,則将其從running中删除并将目前任務的子任務加入隊列中;如果運作失敗,則會啟動備份的任務,并運作失敗的hook。
在launchTask方法中,先判斷是否支援并發執行,如果支援則調用TaskRunner的start()方法,否則調用<code>tskRun.runSequential()</code>方法順序執行,隻有當是MapReduce任務時,才執行并發執行:
最後任務的執行情況,就要看具體的<code>Task<? extends Serializable></code>的實作類的邏輯了。
執行計劃完成:<code>plan.setDone();</code>
6、運作HiveDriverRunHook的後置方法postDriverRun
1、儲存目前查詢狀态
QueryState中儲存了HiveOperation以及目前查詢語句或者指令。
2、建立Context上下文
3、建立ParseDriver對象,然後解析指令、生成AST樹。文法和詞法分析内容,不是本文重點故不做介紹。
簡單歸納來說,解析程包括如下:
詞法分析,生成AST樹,ParseDriver完成。
分析AST樹,AST拆分成查詢子塊,資訊記錄在QB,這個QB在下面幾個階段都需要用到,SemanticAnalyzer.doPhase1完成。
從metastore中擷取表的資訊,SemanticAnalyzer.getMetaData完成。
生成邏輯執行計劃,SemanticAnalyzer.genPlan完成。
優化邏輯執行計劃,Optimizer完成,ParseContext作為上下文資訊進行傳遞。
生成實體執行計劃,SemanticAnalyzer.genMapRedTasks完成。
實體計劃優化,PhysicalOptimizer完成,PhysicalContext作為上下文資訊進行傳遞。
4、讀取環境變量,如果配置了文法分析的hook,參數為:<code>hive.semantic.analyzer.hook</code>,則:先用反射得到<code>AbstractSemanticAnalyzerHook</code>的集合,調用<code>hook.preAnalyze(hookCtx, tree)</code>方法,然後再調用<code>sem.analyze(tree, ctx)</code>方法,該方法才是用來作文法分析的,最後再調用<code>hook.postAnalyze(hookCtx, tree)</code>方法執行一些使用者定義的後置操作;
否則,直接調用<code>sem.analyze(tree, ctx)</code>進行文法分析。
5、校驗執行計劃:<code>sem.validate()</code>
6、建立查詢計劃QueryPlan。
7、初始化FetchTask。
8、得到schema
9、授權校驗工作。
上面分析中,提到了hive的hook機制,hive中一共存在以下幾種hook。
通過hook機制,可以在運作前後做一些使用者想做的事情。如:你可以在文法分析的hook中對hive的操作做一些超級管理者級别的權限判斷;你可以對hive-server2做一些session級别的控制。
本文主要介紹了hive運作過程,包括hive文法詞法解析以及hook機制,任務的最後運作過程取決于具體的<code>Task<? extends Serializable></code>的實作類的邏輯。關于hive文法詞法解析,這一部分沒有做詳細的解釋。
hive Driver類的執行過程如下(該圖是根據hive-0.11版本畫出來的):