如何在 hive udf 中访问配置数据-踩坑记录,方案汇总与对比-udf中可以写sql吗?

简介: 如何在 hive udf 中访问配置数据-踩坑记录,方案汇总与对比-udf中可以写sql吗?

近日我司有个大数据业务系统在某客户现场实时部署时,遇到了一个Hive udf的使用问题,这个问题比较难排查,因为涉及到对Hive的架构原理以及hive sql 解析优化和执行的细节的理解。在此跟大家分享总结下,希望对大家以后使用hive sql 尤其是udf 的编写能有所帮助。

一。问题现象

该客户使用的是 cdh6.2,对 hive 开启了 kerberos 安全认证也使用了sentry插件来进行 hive 表的权限管理,出于安全考量他们禁止在 udf 中直接访问hive 底层 hdfs 上的数据,所以我们的大数据业务系统将要获取的配置信息,即“交易日数据“定义为了 hive 表,然后在 udf 代码中通过建立到 hiveserver2 的 jdbc 连接然后执行 Statement.executeQuery("select close_date from ods_closedate") 的方式来获取交易日数据。

在测试时,通过 beeline 连接到 hiveserver2 然后通过 select hiveudf.lastexchangeday(20200102) 调用 udf 获取上一个交易日,但是实际执行时发现以上 udf 调用并不能成功获取到上一个交易日 20200101,观察发现客户端卡死且没有任何报错信息也没有结果,同时留意到链接同一个 hiveserver2实例的其它客户端能够正常连接到 hiveserver2 也能提交 sql,但是提交的sql 即使是最简单的 “show databases” ,客户端也是处于长时间卡死的状态且没有任何报错信息也没有任何结果。只有重启后 hiveserver2 才能正常对外提供服务。

二。问题原因

首先大家要理解下 Hive 的架构原理和 sql 执行细节:用户通过客户端 (可以是beeline, 也可以是java程序)建立到 hiveserver2 的 jdbc 连接,然后提交hive sql 给 hiveserver2,hiveserver2 收到 sql 后需要做解析编译和优化以生成最终的 mr/tez/spark 任务 (解析编译和优化需要访问 hive metastore service 以获得表和 udf 等的元数据信息),这些 mr/tez/spark 任务在执行时首先需要到 yarn 上申请资源,然后在申请获得的 yarn container 中执行这些任务并将结果返回给 hiveserver2 进而返回给客户端。这些 Sql 包括 sql中的 Udf,其解析编译优化和生成 mr/tez/spark 任务是在 hiveserver2 中进行的,但并不是所有的 sql 和 udf 都会生成 mr/tez/spark 任务,比如 select current_timestamp() 就不会生成 mr/tez/spark 任务,也不需要向 yarn 申请资源获得 container 容器,而是直接在 hiveserver2 中执行的。

该业务系统通过 beeline 客户端连接到 hiveserver2 实例后,通过语句 “select lastexchangeday(20200102)” 调用 Udf 查询交易日数据,该 udf 在hiveserver2 的解析编译和优化过程中也不会生成任何 mr/tez/spark 任务 (因为 hiveserver2 在对语句 “select hiveudf.lastexchangeday(20200102)”进行解析编译优化时通过语法检查发现该 sql 语句并不包含任何 hive 表,所以 hiveserver2 认为不需要生成 mr/tez/spark 任务分布式地执行),所以该 udf 的最终执行也是在 hiveserver2 中执行的,此时由于该 udf 代码本身包含了建立到 hiveserver2 的jdbc连接和执行Statement.executeQuery("select close_date from hs_ods_closedate"),所以其执行过程,就相当于在 hiveserver2 这个 jvm 中建立到同一个hiveserver2 的 Jdbc 连接并提交执行 sql "select close_date from hs_ods_closedate",也就是 hiveserver2 这个 jvm 即是 sql 调用的客户端也是 sql 执行的服务端。在当前的 hiveserver2 实现中,这种调用方式就会引起 hiveserver2 无法响应其它客户端的sql (虽然其它客户端还可以成功连接到该 hiveserver2),也无法完成当前 udf 底层的 sql 调用。

更细节的信息,大家可以参考源码,也可以观察调用时 hiveserver2 的堆栈信息。


三。问题解决方案

其实总结下来,udf中读取配置参数,主要有四种方式:

  • 方案1. 使用一个hdfs文件存储配置参数,该hdfs配置文件一般用csv/json/xml等半结构化格式;udf通过直接读取hdfs文件获取配置参数;用户需要更改配置参数时直接更改本地文件并上传覆盖hdfs上的配置文件;
  • 方案2. 使用一个本地文件存储配置参数,该本地配置文件一般用csv/json/xml/properties等文本格式,且打包到udf对应的jar包中;udf通过读取jar包内嵌的配置文件获取配置参数;用户需要更改配置参数时需要更改本地文件并替换jar包中的配置文件;
  • 方案3. 使用一个hive表存储配置参数,且该表最好是外表且以csv/tsv等文本格式存储;udf通过直接读取该表底层的hdfs文件获得配置参数;用户需要更改配置参数时可以直接使用hive sql dml语句;
  • 方案4. 使用一个hive表存储配置参数; udf在内部代码中通过sql读取该配置参数表获得配置参数;用户需要更改配置参数时可以直接使用hive sql dml语句;==> 以上发生问题的业务系统,我们采用的就是该方案4!该方案的细节和注意项,请继续向下阅读

以上四种方式各有利弊,也都有客户线上采用,具体选用哪个,无非是在配置文件内容更改的便捷性, udf升级运维的便捷性,udf的执行效率,还有客户安全规范,这几个考量点之间的权衡。

不过有一点需要指出,sentry是基于插件机制对hive库和表直接进行的权限管理,如果直接访问库和表底层的hdfs文件就绕过了sentry的安全管理,所以一般使用sentry时确实不建议直接访问hdfs文件,但这也不是绝对的,因为不使用sentry安全机制并不代表就是不安全的,我们完全可以合理使用hdfs对目录和文件的权限管控机制来达到安全的目的,此时可以直接使用hdfs文件或合理使用hive外表,由客户指定hdfs文件或hive外表的具体路径和权限,然后udf执行时通过配置参数获取hdfs文件或hive外表对应的hdfs文件的路径,并直接读取获取配置内容。


四。方案四易踩坑细节分析

其实业界普遍不建议在 hive udf 内部代码中调用 hive sql,因为稍有不慎就可能会出现如上问题现象中描述的 hiveserver2 不响应的情况。但该方式也并非完全行不通,只是在使用上有各种小细节要注意,而且跟不同版本hiveserver2 的解析编译和优化相关代码的具体实现有关:

  • 如果 beeline 或用户 java 程序连接的是 hiveserver2 实例1,而udf内部代码提交的sql是提交到 hiveserver2 实例2, 则不会出现上述问题;
  • 由于hive 老客户端 hive/hive service –cli 在功能上包含了 hive 新客户端 beeline 和 hiveserver2 的功能,所以通过老客户端 hive 提交 udf,而 udf 内部代码中提交 sql 到 hiveserver2 实例上,也是没问题的;
  • 如果用户提交的 udf 在经过 hiveserver2 的解析编译和优化后会生成mr/tez/spark 任务,此时由于 mr/tez/spark 任务是在向 yarn 申请获得的 container 中执行的,所以 udf 内部代码中的 sql 是从 yarn container 中反向提交给 hiveserver2 去执行的,也不会存在上述问题。
  • 但由于 hiveserver2 何时经解析编译和优化会生成 mr/tez/spark 任务,何时不会生成 mr/tez/spark 任务,跟 hiveserver2 不同版本的具体实现有关,也跟我们 udf 的调用方式有关,不好一概而论,所以我们一般不推荐使用这种方式。
  • 经验证,select lastexchangeday(20200102) 不会生成mr/tez/spark任务,select lastexchangeday(current_date) from userTableA 会生成 mr/tez/spark 任务,也即当 udf 参数是常量时不会生成 mr/tez/spark 任务,当 udf 参数是从其他 hive 表中查询获得时是会生成mr/tez/spark 任务的。(在cdh6.2中验证是这样,其他版本差异较大的不一定)。
相关文章
|
12天前
|
SQL 存储 Oracle
Oracle的PL/SQL定义变量和常量:数据的稳定与灵动
【4月更文挑战第19天】在Oracle PL/SQL中,变量和常量扮演着数据存储的关键角色。变量是可变的“魔术盒”,用于存储程序运行时的动态数据,通过`DECLARE`定义,可在循环和条件判断中体现其灵活性。常量则是不可变的“固定牌”,一旦设定值便保持不变,用`CONSTANT`声明,提供程序稳定性和易维护性。通过 `%TYPE`、`NOT NULL`等特性,可以更高效地管理和控制变量与常量,提升代码质量。善用两者,能优化PL/SQL程序的结构和性能。
|
2月前
|
SQL 存储 关系型数据库
一文搞懂SQL优化——如何高效添加数据
**SQL优化关键点:** 1. **批量插入**提高效率,一次性建议不超过500条。 2. **手动事务**减少开销,多条插入语句用一个事务。 3. **主键顺序插入**避免页分裂,提升性能。 4. **使用`LOAD DATA INFILE`**大批量导入快速。 5. **避免主键乱序**,减少不必要的磁盘操作。 6. **选择合适主键类型**,避免UUID或长主键导致的性能问题。 7. **避免主键修改**,保持索引稳定。 这些技巧能优化数据库操作,提升系统性能。
282 4
一文搞懂SQL优化——如何高效添加数据
|
2月前
|
SQL Java 应用服务中间件
Java项目防止SQL注入的四种方案
Java项目防止SQL注入的四种方案
41 0
|
19小时前
|
SQL 机器学习/深度学习 数据采集
数据分享|SQL Server、Visual Studio、tableau对信贷风险数据ETL分析、数据立方体构建可视化
数据分享|SQL Server、Visual Studio、tableau对信贷风险数据ETL分析、数据立方体构建可视化
|
1天前
|
SQL Oracle 关系型数据库
利用 SQL 注入提取数据方法总结
利用 SQL 注入提取数据方法总结
|
2天前
|
SQL 机器学习/深度学习 算法
SQL SERVER ANALYSIS SERVICES决策树、聚类、关联规则挖掘分析电商购物网站的用户行为数据
SQL SERVER ANALYSIS SERVICES决策树、聚类、关联规则挖掘分析电商购物网站的用户行为数据
17 2
|
2天前
|
SQL 机器学习/深度学习 数据挖掘
SQL Server Analysis Services数据挖掘聚类分析职业、地区、餐饮消费水平数据
SQL Server Analysis Services数据挖掘聚类分析职业、地区、餐饮消费水平数据
|
12天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标自定义异常:数据探险家的“专属警示灯”
【4月更文挑战第19天】Oracle PL/SQL中的游标自定义异常是处理数据异常的有效工具,犹如数据探险家的警示灯。通过声明异常名(如`LOW_SALARY_EXCEPTION`)并在满足特定条件(如薪资低于阈值)时使用`RAISE`抛出异常,能灵活应对复杂业务规则。示例代码展示了如何在游标操作中定义和捕获自定义异常,提升代码可读性和维护性,确保在面对数据挑战时能及时响应。掌握自定义异常,让数据管理更从容。
|
12天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
12天前
|
SQL Oracle 安全
Oracle的PL/SQL循环语句:数据的“旋转木马”与“无限之旅”
【4月更文挑战第19天】Oracle PL/SQL中的循环语句(LOOP、EXIT WHEN、FOR、WHILE)是处理数据的关键工具,用于批量操作、报表生成和复杂业务逻辑。LOOP提供无限循环,可通过EXIT WHEN设定退出条件;FOR循环适用于固定次数迭代,WHILE循环基于条件判断执行。有效使用循环能提高效率,但需注意避免无限循环和优化大数据处理性能。掌握循环语句,将使数据处理更加高效和便捷。

热门文章

最新文章