Hive Query生命周期 —— 钩子(Hook)函数篇

无论你通过哪种方式连接Hive(如Hive Cli、HiveServer2),一个HQL语句都要经过Driver的解析和执行,主要涉及HQL解析、编译、优化器处理、执行器执行四个方面。

Hive Query生命周期 —— 钩子(Hook)函数篇
Hive Query生命周期 —— 钩子(Hook)函数篇

以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.PostExecut