1. 即席查询平台简介
-
即席查询平台是数据平台针对即席查询(Ad-Hoc)场景推出的一个解决方案。
-
用户侧提供 SQL 的查询、结果数据的生命周期管理。
-
运维测统一表权限、Hadoop 组账号、Yarn 队列等。
2. ZUE 的定位与同类产品的比较
离线数据开发平台的技术演进:
-
石器时代:Hive 客户端直连
-
青铜时代:beeline 客户端 + Hive Server
-
英雄时代:HUE + Hive Server
-
军团时代:ZUE + Moses + Hive Server
开发工具几个阶段的比较:
Hive Cli | Beeline | HUE | ZUE | |
---|---|---|---|---|
交互方式 | 终端 | 终端 | WEB | WEB |
SQL 支持 | 全类型 | 全类型 | 全类型 | 部分语句 |
表权限控制 | 无 | 无 | table.in | 元数据与权限 |
组账号管理 | 无 | 无 | 支持 | 支持 |
异步查询 | 不支持 | 不支持 | 不支持 | 支持 |
查询结果缓存 | 不支持 | 不支持 | 弱支持 | 支持 |
资源隔离与限制 | 无限制 | 无限制 | 无限制 | 有限制 |
2.1 SQL 的支持
-
Hive Cli、Beeline、HUE 是全功能的客户端工具,提供了完整的 Hive Query 语法的支持以及 HDFS 的管理命令
-
ZUE 限制了可以执行的 SQL 子句类型,把 ZUE 定位为 DML 的平台,将 DDL 划分给元数据管理系统负责。
-
ZUE 仅支持
SELECT
、CREATE TABLE AS
、EXPLAIN
等少数语句,并且禁止通过 ZUE 向线上生产表写入数据。 -
元数据针对 DDL 提供了更加丰富的业务规范与控制,如业务划分、层级划分、表权限控制、变更历史、Location 限制等等。
2.2 表权限控制
-
Hive Cli 和 Beeline 都不具备表权限的功能。
-
HUE 本身不带读写权限的控制,
table.in
作为一种 Hack 的方案先天不足(黑名单)。 -
ZUE 用词法解析获取读写的表,结合元数据做权限的控制。
-
元数据提供了完整的权限申请工作流。
2.3 组账号管理
-
Hive Cli 和 Beeline 没有统一的组账号管理方式,默认以个人账号提交。
-
HUE 的组账号与个人账号等价,无法灵活的切换组账号。
-
Hive Cli、Beeline 和 HUE 大量个人账号的存在导致许多数据出现 owner 的权限问题。
-
ZUE 收敛组账号,从属于业务的数据由统一的组账号进行读写,避免权限问题的发生。
2.4 异步查询
-
Hive Cli、Beeline 和 HUE 的查询操作都是同步,一个客户端会话同一时间只能进行一个查询。关闭客户端或者会话都会导致查询被取消。
-
ZUE 采取异步查询的方式,在同一个窗口可以提交多个查询,多个查询可以并发运行。
2.5 查询结果缓存
-
Hive Cli 和 Beeline 只能手动将查询结果导出保存,否则同一条 SQL 必须重跑才能看到结果。
-
HUE 的查询结果只能在会话过程中查看,一旦页面关闭结果也就丢失了。
-
ZUE 的查询结果缓存 24 小时,重复查看和下载不需要耗费新的计算资源。
2.6 资源隔离与限制
-
Hive Cli、Beeline 和 HUE 无法对用户的查询进行队列的限制,默认提交至
default
队列。 -
Hive Cli、Beeline 和 HUE 运行时可以任意指定队列,无法针对业务线进行资源隔离和计费。
-
ZUE 针对业务线进行队列的限定,保证业务线之间资源的隔离与安全。
3. 功能与架构设计
3.1 HUE 的功能架构缺陷
-
HUE 虽然支持了很多功能,但是本质和 Beeline 并无不同,都是 Thrfit 接口中会话的一种可视化呈现。
-
Thrfit 的会话存在于 HiveServer 中,因此用户的请求必须通过一致性哈希路由到同一台服务器。缺陷在于:1)如果前端请求的路由策略不正确,请求到了其他服务器则该会话的上下文丢失(SET xxx)并且该会话下进行中的查询终止;2)如果某台服务器上 HUE 重启,意味着该服务器上的 Thrfit 会话终结,该服务器上的查询全部自动终止。
-
HUE 的水平扩展实质只能是多个单机节点对总体查询和负载进行分片,单机长时间保持状态。
-
HUE 查询请求量提升时更容易出现线程问题,导致整体不可使用。
-
HUE 虽然界面干净、交互友好,但是本质是适合小团队使用的单机系统。
3.2 ZUE 的整体设计架构
-
将有状态与无状态的部分分离。无状态接口以容器方式部署,可伸缩性好,迭代升级易维护。长时间保持状态与 HiveServer 保持连接的部分抽象出查询中心模块,部署在物理机上。
-
Moses 查询中心通过暴露 RESTFul 的接口提供异步查询的能力,查询完成之后回调请求方的接口。
-
Moses 查询中心每个结点对等,通过持久化与 HiveServer 的会话信息实现服务重启过程中会话不丢失,不影响用户查询。
-
使用 HDFS 和 Redis 来缓存查询的结果,缓存生命周期结束后自动回收存储空间。
4. 实现方案一些细节
4.1 语法限制与表权限
-
对 SQL 进行词法解析,得到抽象语法树。
-
对抽象语法树进行后续遍历获得语句的类型以及读写的表。
4.1.1 词法分析实例
举例:
insert overwrite table tb.tb_2 select * from tb.tb_1;
解析成抽象语法树,采用后续遍历进行打印可以得到结果:
nil TOK_QUERY TOK_FROM TOK_TABREF TOK_TABNAME tb tb_1 TOK_INSERT TOK_DESTINATION TOK_TAB TOK_TABNAME tb tb_2 TOK_SELECT TOK_SELEXPR TOK_ALLCOLREF <EOF>
几种 token 代表的含义:
-
TOK_TAB
:写入目标表tb.tb_2
。 -
TOK_TABREF
:查询数据来源表tb.tb_1
。 -
TOK_INSERT
:语句的类型。
4.1.2 其他工具与缺陷
Hive 自己提供了一个血缘解析的工具:org.apache.hadoop.hive.ql.tools.LineageInfo
。
缺陷:
-
缺少上下文的支持,比如上文使用
USE <db>
语句,那么解析出来的输入表只包含表名,缺少库名。 -
反引号转义符需要另行清理。
-
对于
CTE
语句中的别名无法处理。
4.2 异步查询
-
与 HUE 的区别:将用户会话与 Thrift 会话解耦,WEB 交互无状态,封装 Thrfit 会话。
-
从 JDBC 获得的启示:底层原理同 Beeline 一致,对 Thrift 进行封装,通过覆盖特定的会话配置支持会话恢复重连,查询中心作为一个查询中间件可重启升级不影响用户查询。
config.put("hive.server2.session.check.interval", "1h");
config.put("hive.server2.close.session.on.disconnect", "false");
config.put("hive.server2.idle.session.timeout", "24h");
config.put("hive.server2.idle.operation.timeout", "24h");
private synchronized TOperationHandle submitQuery(String sql) throws TException {
log.info("Start to submit sql of task {} with content:\n{}", this.taskMeta.getTaskId(), sql);
TExecuteStatementReq execReq = new TExecuteStatementReq(this.sessionHandle, sql);
execReq.setRunAsync(true);
TExecuteStatementResp execResp = this.client.ExecuteStatement(execReq);
log.info("execResp = " + execResp);
this.checkStatus(execResp.getStatus());
return execResp.getOperationHandle();
}
4.3 结果缓存
结果缓存分为三种:
-
较复杂 SQL 或者大数据量的查询结果通过改写 SQL 将结果以
Avro
的形式存储在 HDFS 上,定时回收存储空间。 -
简单 SQL 如单表查询直接将结果缓存于 Redis 中,设置缓存的过期时间。
-
使用
CTAS
创建的临时表,定时从临时库中清除。
5. 本季度的迭代方向
-
更友好的故障排查(
Yarn Application
日志)与异常诊断。 -
更多元化的大数据计算引擎的集成(如
Presto
)。
6. FAQ
-
code 2 如何排查
-
Method Not Found
-
job counter 不准
-
read timeout