引言
目前数据平台使用Hadoop构建,为了方便数据分析师的工作,使用Hive对Hadoop MapReduce任务进行封装,我们面对的不再是一个个的MR任务,而是一条条的SQL语句。数据平台内部通过类似JDBC的接口与HiveServer进行交互,仅仅能够感知到一条SQL的开始与结束,而中间的这个过程通常是漫长的(两个因素:数据量、SQL复杂度),某些场景下用户需要了解这条SQL语句的执行进度,从而为我们引入以下几个问题:
(1)通过JDBC接口执行一条SQL语句时,这条SQL语句被转换成几个MR任务,每个MR任务的JobId是多少,如何维护这条SQL语句与MR任务的对应关系?
(2)如何获取MR任务的运行状态,通过JobClient?
(3)通过HiveServer是否可以获取到上述信息?
思路
当我们在终端下执行命令“hive”后,会看到有如下输出:
Hive有会话(Session)的概念,而这次会话中的所有日志消息将会输出到这个日志文件中,包含SQL语句的执行日志,查看这个日志文件可以看到以下信息:
QueryStart行日志包含QUERY_STRING、QUERY_ID。
TaskStart行日志包含TASK_ID、QUERY_ID。
TaskProgress行日志包含TASK_HADOOP_PROGRESS、TASK_ID、QUERY_ID、TASK_HADOOP_ID,其中TASK_HADOOP_PROGRESS中可以获取到map、reduce进度。
TaskEnd行日志包含TASK_HADOOP_PROGRESS、TASK_ID、QUERY_ID、TASK_HADOOP_ID。
QueryEnd行日志包含QUERY_STRING、QUERY_ID。
由上可知,QueryStart、TaskStart、TaskProgress、TaskEnd(一个复杂的Query可能会产生多个Task)、QueryEnd覆盖整个查询的执行过程,通过对这些行日志的解析,我们就可以获取到Hive SQL的执行状态。
此外,还有SessionStart、SessionEnd,由于使用过程中发现SessionEnd日志有时不被输出,因此没有使用这两个状态。
会话的日志文件存储在HiveServer的本地磁盘中,而实际应用中我们有多台HiveServer提供服务,因此我们需要能够统一收集所有HiveServer的会话日志。
通过对Hive源码的分析发现,每次Hive执行语句时都会执行一些“Hook”(PreHook),代码如下:
通过会话日志、PreHook,我们基本可以整理出以下思路:
在PreHook中启动线程监听会话日志的输出(类型Linux的tailf),将这些日志信息统一收集到某一服务中,统一处理后做进度展示。
实现
我们构建了一个Rest API服务,一部分用于接收由PreHook发送的会话日志信息,另一部分用于对外提供进度展示。
PreHook要求实现接口ExecuteWithHookContext,如下:
通过hookContext我们可以获取到以下信息:
QueryId:
QueryStr:
HadoopJobName:
Jobs:
HistFileName:
为了保证后续对会话日志的接收,我们需要在查询执行伊始就将上述信息发送给Rest API服务,如下:
然后就是对会话日志的输出监听(即tailer),我们使用Apache Commons IO中的Tailer完成些功能,如下:
Tailer实际上启动一个后台线程,并通过listener完成数据行的处理,而一次会话中可能执行多条查询语句,而每一次执行查询语句时都会导致PreHook的执行,因此我们需要避免同一会话中对histFileName多次“tailf”,需要维护已被“tailf”的文件,而且Tailer实例是需要被“stop”的,多数时候无法获取到SessionEnd数据行,需要通过其它方式能够终止会话已经消失的Tailer线程。为此专门设计了TailerTracker(单例,即TAILER_TRACKER)。
TailerTracker维护着一个记录列表:
维护着成对的tailer与listener实例,其中listener实例中维护着对应tailer实例中最后一次新数据产生的时间,如果tailer实例在设定的时间内都没有新数据产生,则应该对其执行stop,核心代码如下:
判断某一个会话文件是否已经被“tailer”,代码如下:
标记一个会话文件已经被“tailer”,代码如下:
会话日志数据行的输出实际由FileTailerListener(继承自TailerListenerAdapter)完成,代码如下:
每处理一行数据,都要更新一下时间戳lastHandleTime,而QueryStart、QueryEnd、TaskStart、TaskProgress、TaskEnd的数据行会通过不同的Rest API Post。
至此,HiveServer的会话日志收集过程完毕,而Rest服务则需要通过这些收集到的数据完成Hive SQL进度跟踪。
我们在通过JDBC接口与HiveServer交互时,是无法获取到QueryId的,但是我们可以通过属性mapred.job.name设置Hive SQL执行时的MR JobName,JobName代表查询名称,需要唯一,同时我们需要维护JobName与QueryId的对应关系。
在Rest服务内部设计实现ProgressController,用以维护JobName与QueryId的对应关系,同时使用QueryId跟踪Hive SQL执行进度,核心变量如下:
目前Hive SQL的进度记录仅仅在内存里维护(超过一定时间后,这些进度信息便不再有价值),因此需要控制内存中进度记录的数量,这一点是通过记录每一条SQL相关进度信息的最后更新时间(lastUpdateTime)来实现的,过期即被清除。
lastUpdateTime:维护JobName(即某个查询)记录最后更新时间;
jobNameToQueryId:维护JobName与QueryId的对应关系;
querys:维护QueryId与Hive SQL执行进度(QueryProgress)的对应关系。
QueryProgress内部结构如下:
queryId:查询ID;
sql:查询语句;
jobs:查询被转换成MapRecude Job的数量;
taskProgresses:维护TaskId与MapReduce的执行进度的对应关系;
startTime:查询的起始时间;
stopTime:查询的终止时间;
state:查询状态。
TaskProgress内部结构如下:
taskId:TaskId(Stage-1、Stage-2、...);
taskHadoopId:Task对应的Hadoop MapReduce Job Id;
map:Hadoop MapReduce map进度百分比值;
reduce:Hadoop MapReduce reduce进度百分比值;
startTime:Task起始时间;
stopTime:Task截止时间;
state:Task运行状态。
当收到query/init的请求时,执行ProgressController queryInit方法,代码如下:
当收到query/start的请求时,执行ProgressController queryStart方法,代码如下:
当收到task/start的请求时,执行ProgressController taskStart方法,代码如下:
当收到task/progress的请求时,执行ProgressController taskProgress方法,代码如下:
当收到task/end的请求时,执行ProgressController taskEnd方法,代码如下:
当收到query/end的请求时,执行ProgressController queryEnd方法,代码如下:
其中ProgressController还承担着定时清理的工作,代码如下:
进度示例
不足
Hive SQL执行进度数据维护在内存中,而且Rest服务为单点。
- Hive SQL 监控系统 - Hive Falcon
1.概述 在开发工作当中,提交 Hadoop 任务,任务的运行详情,这是我们所关心的,当业务并不复杂的时候,我们可以使用 Hadoop 提供的命令工具去管理 YARN 中的任务.在编写 Hive SQ ...
- SQL Server监控清单
SQL Server监控清单 一. 服务器1. 状态监控(1) 服务器是否可访问?(2) 相应的数据库服务是否启用?(3) 操作系统事件日志中的错误或告警(4) 磁盘可用空间 服务器状态监控,不管使用 ...
- Hive SQL语法总结
Hive是一个数据仓库基础的应用工具,在Hadoop中用来处理结构化数据,它架构在Hadoop之上,通过SQL来对数据进行操作. Hive 查询操作过程严格遵守Hadoop MapReduce 的作业 ...
- SQL Server 监控系列(文章索引)
一.前言(Introduction) SQL Server监控在很多时候可以帮助我们了解数据库做了些什么,比如谁谁在什么时候修改了表结构,谁谁在删除了某个对象,当这些事情发生了,老板在后面追着说这是谁 ...
- 【hive】——Hive sql语法详解
Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件映射为一张数据库表,并提供完整的SQL查 ...
- hive sql 语法详解
Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件映射为一张数据库表,并提供完整的SQL查 ...
- Hive sql 语法解读
一. 创建表 在官方的wiki里,example是这种: Sql代码 CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name d ...
- Spark(Hive) SQL中UDF的使用(Python)
相对于使用MapReduce或者Spark Application的方式进行数据分析,使用Hive SQL或Spark SQL能为我们省去不少的代码工作量,而Hive SQL或Spark SQL本身内 ...
- Spark(Hive) SQL数据类型使用详解(Python)
Spark SQL使用时需要有若干“表”的存在,这些“表”可以来自于Hive,也可以来自“临时表”.如果“表”来自于Hive,它的模式(列名.列类型等)在创建时已经确定,一般情况下我们直接通过Spar ...
随机推荐
- 多线程下的performSelector和NSThread的使用
多线程下的performSelector和NSThread的使用 NSThread的多线程使用: 我们可以使用这两种方法来使用线程中的问题 - (id)initWithTarget:(id)targe ...
- [转] git reset简介
http://blog.csdn.net/hudashi/article/details/7664464 http://guibin.iteye.com/blog/1014369 http://hi. ...
- php-fpm 启动参数及重要配置详解<转>
原文地址 http://levi.cg.am/archives/3127 约定几个目录 /usr/local/php/sbin/php-fpm /usr/local/php/etc/php-fpm. ...
- 【转】string常用函数
原文地址:http://hi.baidu.com/baowup/blog/item/3a27465c86d71546faf2c066.html/cmtid/de1ef3f0de7554a0a40f52 ...
- Vijos P1325桐桐的糖果计划(有向图双连通分量)
/*重边不能删 不能删 不能删...*/ #include<iostream> #include<cstdio> #include<cstring> #define ...
- EXCEL表格常用函数使用的难点
1. INDIRECT(ref_text,逻辑值) 返回由文本字符串指定的引用.此函数立即对引用进行计算,并显示其内容.ref_text,文本引用说明, (1) A1-样式的引用(逻辑值,T,缺省) ...
- 织梦(dedecms)如何清空全部文章和删除后新增文章id号归1的方法
很多朋友在使用织梦程序做网站的过程中,难免需要添加一些测试文章用于测试网站功能模板等,还有些人朋友网站改版需要变更内容的时候,面对着众多的老文章后总是一筹莫展! 由于织梦后台并不自带一键删除整站文章的 ...
- Xcode6中如何修改文件中自动创建的Created by和Copyright
转自: http://blog.csdn.net/bjourney/article/details/46832159 在Xcode6创建问的时候,会自动生成注释 // Created byxxx o ...
- javascript基础学习(十五)
javascript之cookie 学习要点: cookie介绍 创建与获取cookie cookie的编码 cookie的生存期 cookie的路径 cookie的domain cookie的sec ...
- 在SpringMVC框架下建立Web项目时web.xml到底该写些什么呢?
刚刚初学Spring MVC,却连一个简单的helloworld都搞的懵懵懂懂的,配置文件搞不清,各种文件之间的逻辑关系也不懂,连续看了好些日子的Spring MVC了,今天终于下定决心,每天记录一点 ...