- 数据平台上需要封装Hive查询,只提供API给业务方使用,代码中通过Hive JDBC完成将查询语句向Hive提交,等待执行完成,结果解析的功能.
- 用户提交查询之后意识到查询语句错误(非语法错误),不想等待错误的语句执行完成后再次提交. 由于用户没有yarn client的权限,kill task的操作也需要通过API提供,因此在提交查询语句时需要获取其在Yarn上的
Application Id
.- Hive在执行层面加装了Tez,不是那个最初的Hive了.
在网上研究了一番之后,思路主要有两种:
HiveStatement
获取查询日志后进行解析,得到Application Id
Application Id
第一种思路实现起来简单,但是不够优雅,而且在并发查询的情况下会是什么效果没有测试过.
第二种查询由于Tez的原因,尝试了很多种方案,都不能有效的设置查询标识符.
该功能测试的通用连接代码如下:
private static String driverName = "org.apache.hive.jdbc.HiveDriver";
Class.forName(driverName);
String url = "jdbc:hive2://:10000/";
Properties info = new Properties();
info.setProperty("user", "bigdata");
info.setProperty("password", "******");
Connection conn = DriverManager.getConnection(url, info);
HiveStatement stmt = (HiveStatement) conn.createStatement();
String table = "table_name";
ResultSet result = stmt.executeQuery("SELECT COUNT(*) FROM " + table);
日志解析的Java代码如下:
String yarn_app_id = "";
for (String log : stmt.getQueryLog()) {
if (log.contains("App id")) {
yarn_app_id = log.substring(log.indexOf("App id") + 7, log.length() - 1);
}
}
System.out.println(yarn_app_id);
这个办法想起来简单,实际操作起来,绕了十万八千里的路.
最开始拍脑袋想到去修改Application Name
,一般的以为设置mapred.job.name
这个参数就好了. 要想在运行时修改配置参数,需要在hive-site.xml
中加入配置项hive.security.authorization.sqlstd.confwhitelist
和hive.security.authorization.sqlstd.confwhitelist.append
.
我的配置最终如下:
<property>
<name>hive.security.authorization.sqlstd.confwhitelist.appendname>
<value>hive.*|mapred.*|tez.*|queue.*value>
property>
<property>
<name>hive.security.authorization.sqlstd.confwhitelistname>
<value>hive.*|mapred.*|tez.*|queue.*value>
property>
但是mapred.job.name
这个配置并不能生效. 类似的配置像hive.query.name
,也没有作用. Debug了一下,发现在HiveDriver
层是能够读取并写入conf的,而最终没有生效,不能确定在Tez层发生了什么.
从网上的资料来看,Tez层设置的Application Name
是按照HIVE-
来设置的. 这个配置项虽然不推荐修改,但是通过命令行提供Hive(On Tez)查询的时候,它是能够生效的。但是在代码中传入配置项,来实例化Connection
,却依然不起作用.
凭感觉判断肯定和Tez有关,网上的解答不多,找了相关的一些FAQ和Mail,大概也是这样的判断. 不过这部分都是都还只是猜测,于是想试试看能不能在代码中成功修改tez的配置. 最简单的锁定在queue.name
这项上. 直接改mapred.job.queue.name
并没什么卵用,但是在尝试通过tez.queue.name
配置项进行修改时,奇迹出现了.
这个尝试可以基本断定,Hive On Tez在通过Hive JDBC提交的时候,只能成功读取(或者成功设置)Tez支持的配置项。Tez 0.9.1支持的所有配置项如下:
Tez 0.9.1配置项
在该文档中可以看到之前用来修改提交队列的配置:
Property Name | Default Value | Description |
---|---|---|
tez.queue.name | null | String value. The queue name for all jobs being submitted from a given client. |
不幸的是,TezConfiguration
里没有能够修改Application Name
的配置项. 正当万念俱灰之际,正是船到桥头自然直,柳暗花明又一村. 虽然没找到能够修改Application Name
的配置项,但是在模糊查询的时候,发现了这个配置tez.application.tags
. 于是顺藤摸瓜的,研究了一下Yarn对于Application Tag
的支持.
Property Name | Default Value | Description |
---|---|---|
tez.application.tag | null | String value. Tags for the job that will be passed to YARN at submission time. Queries to YARN for applications can filter on these tags. |
尝试了一下,通过JDBC的方式成功设置.Yarn对于tag的使用应该是用来过滤出某组应用的,这里我就曲线救国,借用一下用来存放查询的唯一标识符.
首先,启动Yarn Client:
YarnClient client = YarnClient.createYarnClient();
Configuration conf = new Configuration();
// conf.set();
client.init(conf);
client.start();
提交作业前设置property:
String url = "jdbc:hive2://:10000/";
Properties info = new Properties();
info.setProperty("user", "bigdata");
info.setProperty("password", "******");
info.setProperty("hiveconf:hive.execution.engine", "tez");
info.setProperty("hiveconf:tez.application.tags", "hive-client-job-test");
获取ApplicationReport
:
Set applicationTypes = Sets.newHashSet();
applicationTypes.add("TEZ");
Set applicationTags = Sets.newHashSet();
applicationTags.add("hive-client-job-test");
Set applicationStates = Sets.newHashSet();
applicationStates.add(YarnApplicationState.ACCEPTED);
applicationStates.add(YarnApplicationState.FINISHED);
applicationStates.add(YarnApplicationState.RUNNING);
EnumSet enumStates = Sets.newEnumSet(applicationStates, YarnApplicationState.class);
List reports = client.getApplications(applicationTypes, enumStates, applicationTags);
for (ApplicationReport report : reports) {
System.out.println(report.getApplicationId());
}
虽然
client.getApplications()
方法返回的是一个List
,但是因为我的Tag是唯一生成的,所以实际上只会返回一个Application Id
done!
这种方法是我觉得相对来说比较优雅的解决方案了,暂时没有想出更好的办法了,如果有更好方式了话,欢迎评论交流!