Hive Query生命週期 —— 鉤子(Hook)函式篇

大資料學習與分享發表於2021-01-18

無論你通過哪種方式連線Hive(如Hive Cli、HiveServer2),一個HQL語句都要經過Driver的解析和執行,主要涉及HQL解析、編譯、優化器處理、執行器執行四個方面。

以Hive目前原生支援計算引擎MapReduce為例,具體處理流程如下:

  1. HQL解析生成AST語法樹Antlr定義SQL的語法規則,完成SQL詞法和語法解析,將SQL轉化為抽象語法樹AST Tree
  2. 語法分析得到QueryBlock遍歷AST Tree,抽象出查詢的基本組成單元QueryBlock
  3. 生成邏輯執行計劃遍歷QueryBlock,翻譯為執行操作樹Operator Tree
  4. Logical Optimizer Operator進行邏輯優化邏輯層優化器進行OperatorTree變換,合併不必要的ReduceSinkOperator,減少shuffle資料量
  5. 生成物理執行計劃Task Plan遍歷Operator Tree,翻譯為MapReduce任務
  6. 物理優化Task Tree,構建執行計劃QueryPlan物理層優化器進行MapReduce任務的變換,生成最終的執行計劃
  7. 表以及其他操作鑑權
  8. 執行引擎執行

在Hive Query整個生命週期中,會有如下鉤子函式被執行:

HiveDriverRunHook的preDriverRun

該鉤子函式由引數hive.exec.driver.run.hooks控制,決定要執行的pre hooks,多個鉤子實現類以逗號間隔,鉤子需實現 org.apache.hadoop.hive.ql.HiveDriverRunHook介面。


HiveSemanticAnalyzerHook的preAnalyze

在Driver開始run之前,HQL經過解析會進入編譯階段的語法分析,而在語法分析前會經過鉤子HiveSemanticAnalyzerHook的preAnalyze方法處理。該鉤子函式由hive.semantic.analyzer.hook配置,鉤子需實現org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHook介面。

 

HiveSemanticAnalyzerHook的postAnalyze

與preAnalyze同屬於一個鉤子類,配置引數相同,會執行所有配置的語義分析hooks,但它位於Hive的語法分析之後,可以獲取HQL的輸入和輸出表及分割槽資訊,以及語法分析得到的task資訊,由此可以判斷是否是需要分散式執行的任務,以及執行引擎是什麼。

生成執行計劃之前的redactor鉤子

該鉤子由hive.exec.query.redactor.hooks配置,多個實現類以逗號間隔,鉤子需繼承org.apache.hadoop.hive.ql.hooks.Redactor抽象類,並替換redactQuery方法。

這個鉤子函式是在語法分析之後,生成QueryPlan之前,所以執行它的時候語法分析已完成,具體要跑的任務已定,這個鉤子的目的在於完成QueryString的替換,比如QueryString中包含敏感的表或欄位資訊,在這裡都可以完成替換,從而在Yarn的RM介面或其他方式查詢該任務的時候,會顯示經過替換後的HQL。

task執行前的preExecutionHook

在執行計劃QueryPlan生成完,並通過鑑權後,就會執行具體的task,而task執行之前會經過一個鉤子函式,鉤子函式由hive.exec.pre.hooks配置,多個鉤子實現類以逗號間隔。實現方式:

1)實現org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext

通過實現該介面的run方法,執行所有的pre-execution hooks

// Pre/Post Execute Hook can run with the HookContext
public interface ExecuteWithHookContext extends Hook {

/** hookContext: The hook context passed to each hooks.
   *  HookContext帶有執行計劃、Hive的配置資訊、Lineage、UGI、提交的使用者以及輸入輸出表等資訊
   */
void run(HookContext hookContext) throws Exception;
}

 

2)實現org.apache.hadoop.hive.ql.hooks.PreExecute

 

該介面的run方法已經標註為過時,並且相對於ExecuteWithHookContext,PreExecute提供的資訊可能不能完全滿足我們的業務需求。

public interface PreExecute extends Hook {

/**
   * The run command that is called just before the execution of the query.
   * SessionState、UGI、HQL輸入表及分割槽資訊,HQL輸出表、分割槽以及本地和hdfs檔案目錄資訊
   */
@Deprecated
public void run(SessionState sess, Set<ReadEntity> inputs,Set<WriteEntity> outputs, UserGroupInformation ugi) throws Exception;
}

 

 task執行失敗時的ON_FAILURE_HOOKS

task執行失敗時,Hive會呼叫這個hook執行一些處理措施。該鉤子由引數hive.exec.failure.hooks配置,多個鉤子實現類以逗號間隔。需實實現org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext介面。

 

task執行完成時的postExecutionHook

在task任務執行完成後執行。如果task失敗,會先執行ON_FAILURE_HOOKS,之後執行postExecutionHook,該鉤子由引數hive.exec.post.hooks指定的hooks(多個鉤子實現類以逗號間隔)執行post execution hooks。實現方式:

1)實現org.apache.hadoop.hive.ql.hooks.ExecuteWithHookContext

2)實現org.apache.hadoop.hive.ql.hooks.PostExecute

ExecuteWithHookContext和PostExecute跟分別與上述task執行前的preExecutionHook、PreExecute對應,這裡不再贅述。

 

HiveDriverRunHook的postDriverRun

在查詢完成執行之後以及將結果返回給客戶端之前執行,與preDriverRun對應。

此外,Hive中已經有一些內建實現的hook,下面舉一些例子以及它們的主要作用:

ATSHook:實現了ExecuteWithHookContext,將查詢和計劃資訊推送到Yarn App Timeline Server。

DriverTestHook:實現了HiveDriverRunHook的preDriverRun方法(對postDriverRun是空實現),用於列印輸出的命令

EnforceReadOnlyTables:pre execute hook,實現了ExecuteWithHookContext,用於阻止修改只讀表。

LineageLogger:實現了ExecuteWithHookContext,它將查詢的血統資訊記錄到日誌檔案中。LineageInfo包含有關query血統的所有資訊。

PreExecutePrinter和PostExecutePrinter:pre和post hook的示例,它將引數列印輸出。

PostExecTezSummaryPrinter:post execution hook,實現了ExecuteWithHookContext,可以列印Hive Tez計數器的相關資訊。

PostExecOrcFileDump:post execution hook,實現了ExecuteWithHookContext,用於列印ORC檔案資訊。

UpdateInputAccessTimeHook:pre execution hook,可在執行查詢之前更新所有輸入表的訪問時間。

特別強調一下LineageLogger和LineageInfo,對於做Hive血緣關係分析很有參考價值,當然Hive血緣分析不是本篇文章的重點,這裡先不做展開。

通過對上面Hive中hook的執行"位置"和作用,以及Hive本身實現的一些Hook,分析可知:自定義hook,比如實現一個pre execution hook。

首先在maven的pom中引入hive-exec的依賴,如:

<dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>2.1.0</version>
</dependency>

 

此外,還需建立一個實現ExecuteWithHookContext的類,實現其中的run方法,並設定相應的引數,使自定義的hook類生效。

最後,通過一張圖,來對Hive Hook做個總結:

關聯文章:
Hive Join優化
Apache Hive

相關文章