线上数据问题排查案例分享-因为 HMS 和底层 orc 文件中某字段的数据精度不一致造成的数据丢失问题

简介: 线上数据问题排查案例分享-因为 HMS 和底层 orc 文件中某字段的数据精度不一致造成的数据丢失问题

大家好,我是明哥,本篇文章跟大家分享一次线上数据问题的排查案例,并总结下背后的技术背景和最佳实践,希望对大家有所帮助。

1. 避坑指南和最佳实践

先说下通过本案例总结的避坑指南和最佳实践。

  • hive 的元数据服务 hms 和表底层的 orc 文件中都存储了表的元数据信息,两者天然是割裂的,当两者信息不一致时,容易出现各种奇怪的数据问题;
  • 为避免潜在的数据问题,开发人员需要确保 hms 和 orc 文件中元数据信息的一致,为此应尽量避免更改 hive orc 表字段的数据类型(尤其需要避免对已存储了数据的 orc 表字段做数据类型不兼容的修改);
  • 为避免潜在的数据问题,使用同步工具如 datax 等直接同步数据到 orc 文件时,orc 文件也应该尽量使用对应表在 HMS 中定义的数据类型和数据精度来进行数据同步;
  • 为避免潜在的数据问题,使用 SQL 语句进行数据查询操作时,在数据类型不一致时,应尽量使用 CAST 进行显示转换而不依赖 HIVE SQL 的隐式转换机制;

2. 问题现象

某客户现场部分 HIVE ORC 表在各层的数据条数不一致,存在数据丢失问题。

比如对于 hive orc 表 hs_sr.sr_xxx/hs_ods.ods_xxx/hs_tmp.tmp_pxxx, 使用 count(1) 查询,发现 hs_sr 和 hs_ods 记录条数一致,但 hs_tmp 层则缺少了400条左右数据。

进一步查询发现,指定条件如 prod_code 查询某条数据时,在 hs_sr 层可以查到该条数据但在 hs_tmp 层查不到该条数据,而在 hs_ods 层查询该条数据时, 只要查询字段列表中包含 prod_scale 字段就会查不到该条数据,而查询字段列表不包含 prod_scale 字段就可以查询到该条数据。

备注: ***本案例中,数据链路为使用 datax 从上游交易系统 oracle 采集到 hive 中的 hs_sr 层,然后使用 hive sql 对 hs_sr 层进行加工处理后写入到 hs_ods 层,再经过 hive sql 进一步加工处理后写到 hs_tmp 层。

3. 问题原因-概述

简单来讲,问题原因是 prod_scale 字段在hive表中的数据类型和数据精度跟hive表底层 orc 文件中的数据类型和数据精度不一致,当 orc文件中部分记录 prod_scale 字段实际存储的值大于 hive 中定义的该字段的精度时,hive 查询该字段并写入到下游 ORC 表时会隐式转换为 NULL 值,而部分版本的 HIVE 在将 NULL 值写入 ORC 文件时有 BUG,会造成底层 ORC 文件中部分记录该字段不可读,所以后续 hive 再次在有问题的ORC文件中查询问题字段并插入最下游的 ORC 表时,下游表中就缺失了部分记录。

4. 解决方案

解决方案按照思路不同分为两种,一种是业务侧的调整,一种是平台侧/工具侧的调整。

4.1 业务侧调整

业务侧调整,可以调整 hive 中相关表相关字段在 DDL 定义中的数据类型和数据精度,使之与上游交易系统 ORALCE 中相关字段的数据类型和数据精度一致,比如这里发现的 prod_scale 字段应从 decimal(15,4) 调整为 decimal(18,4);(查询上游交易系统 oracle 中的数据,发现确实有部分记录的 prod_scale 字段值比 decimal(15,4)精度更大,且业务确认这部分数据是正常数据,故应该调整 HIVE 中字段的数据类型和数据精度与上游一致);

4.2 平台侧/工具侧调整

本案例中使用了 datax 从上游 oralce 同步数据到 hive orc 表,故可以对 datax 同步作业进行调整:datax 同步数据时,数据类型和数据精度应该以目标 HIVE 表中定义的数据类型和数据精度为准,对于 decimal 字段也应该以目标hive表中的定义为准,而不是全部使用默认的最大精度 decimal(38,18),从而避免 orc 文件和 hms 中相关元数据信息的不一致,减少后续数据类型隐式转换等操作带来的潜在问题。(datax 同步作业调整后,在数据同步过程中,如果遇到上游 ORACLE 数据精度大于HIVE目标表的数据精度,同步作业会报错退出,从而能第一时间暴露数据问题确保数据质量,而不会将数据质量问题带到下游)。

备注: 「由于开源的 datax 并不支持 hive 的 decimal 数据类型,而 金融行业对数据准确性普遍要求较高,故我司内部对 datax 做了增强,支持 hive 的 decimal 数据类型。」**

5. 问题原因-技术细节

  • 本案例中数据链路如下:使用 datax 从上游交易系统 oracle 采集到 hive 中的 hs_sr 层,然后使用 hive sql 对 hs_sr 层进行加工处理后写入到 hs_ods 层,再经过 hive sql 进一步加工处理后写到 hs_tmp 层;
  • 本案例中,hive 中 hs_sr/hs-ods/hs_tmp 层相关表中关键字段 prod_scale 都被定义为了decimal(15,4), 而上游 ORACLE 中该字段类型为 decimal(18,4);
  • orc 文件:采集上游 oracle 表数据并写入 hive orc 表时,对于 decimal 类型的字段,当前 datax 作业使用的都是 hive 默认的最大精度即 decimal(38,18),所以所有记录所有字段无论精度大小都能被同步到 ORC 文件中;
  • hs_sr 层表:但 HIVE 的 hs_sr 层表中该字段被定义为了更小精度 decimal(15,4),跟底层orc文件中的 decimal(38,18) 并不一致,所以 hive 查询该字段时就会隐式转换为目标类型 decimal(15,4),此时更大精度的值会被转换为 NULL 值进行处理,所以 hs_sr 层的表查询时不会缺少记录,但大精度的字段值会被显示为 NULL;
  • hs_ods 层表:在查询 hs_sr 层表数据再写入 hs_ods 层表时,由于上述隐式转换的原因,部分大精度字段值会被转换为 NULL 值进行处理,而部分版本的 HIVE 在将 NULL 值写入 ORC 文件时有 BUG,会造成底层 ORC 文件中部分记录该字段不可读,具体哪些记录该字段受到影响跟底层 orc 文件中对应的 stripe 中存储了哪些记录的该字段有关,所以 hs_ods 层表只要查询字段列表中包含 prod_scale 字段就会查不到该条数据,而查询字段列表不包含 prod_scale 字段就可以查询到该条数据,同时使用 count(1) 也会发现数据条数没有缺失;
  • hs_tmp 层表:后续查询 hs_ods 层表数据并写入 hs_tmp 层表时,由于 hs_ods 层表底层的 orc 文件中部分 stripe 有问题,所以当查询字段列表包含 prod_scale 字段时,对应 stripe 中的记录都会受到影响查询不到,最终插入 hs_tmp 层的数据也就缺失了这部分记录,使用 count(1) 也会发现数据条数有缺失,即最终出现了数据丢失问题;

6. 技术背景

  • ORC 文件是自描述格式,orc 和 hms 中都存储了表的元数据信息,所以二者天然是割裂的;
  • 当 hive 查询 ORC 表数据时,如果 orc 文件和 hms 中字段类型元数据信息不一致就会涉及到隐式转换;
  • HIVE 并不是 ANSI dialect compliant 的,即 HIVE 并不符合 ANSI SQL 标准,在处理无效数据时会返回NULL值而作业不会报错;
  • hive 中 decimal 类型的默认精度也即最大精度是 decimal(38,18), 当 decimal 类型的字段值在转换为更小精度比如 decimal(15,4) 时,较大精度的值会被转换为 NULL 值(隐式和显示转换都是如此);
  • 部分老版本的 hive 写 ORC 文件时在处理隐式转换的 NULL 值时有 BUG,会造成底层写入的 ORC 文件中的部分记录该字段不可读,但作业不会报错,具体哪些记录受到影响跟底层 orc 文件中对应 stripe 存储了哪些记录该字段有关;
  • 可以使用工具如 hive --orcfiledump xx 来验证表底层 orc 文件的完整性;
  1. 相关JIRA

https://issues.apache.org/jira/browse/HIVE-13083

image.png

相关文章
|
机器学习/深度学习 人工智能 自然语言处理
图解机器学习 | GBDT模型详解
GBDT是一种迭代的决策树算法,将决策树与集成思想进行了有效的结合。本文讲解GBDT算法的Boosting核心思想、训练过程、优缺点、与随机森林的对比、以及Python代码实现。
9052 2
图解机器学习 | GBDT模型详解
|
Arthas 监控 Java
Arthas 概述 | 学习笔记
快速学习 Arthas 概述
Arthas 概述 | 学习笔记
|
分布式计算 监控 大数据
什么是 Spark Driver,它的职责是什么?
【8月更文挑战第14天】
900 5
|
UED 开发者 Python
Python并发编程新纪元:异步编程如何重塑IO与CPU密集型任务的处理方式?
在Python编程中,异步编程作为一种非阻塞模式,通过允许程序在等待IO操作时继续执行其他任务,提高了程序的响应性和吞吐量。与传统同步编程相比,它减少了线程等待时间,尤其在处理IO密集型任务时表现出色,如使用`asyncio`库进行异步HTTP请求。尽管对CPU密集型任务的直接提升有限,但结合多进程或多线程可间接提高效率。异步编程虽强大,但也带来了代码复杂度增加和调试难度提升等挑战,需要开发者掌握最佳实践来克服这些问题。随着其技术的成熟,异步编程正在逐步改变我们处理IO与CPU密集型任务的方式,成为提升性能和优化用户体验的重要工具。
200 0
|
JavaScript 前端开发 程序员
Vue学习之--------Vue生命周期beforeCreate、created、beforeMount、mounted、beforeDestroy 。。。(图解详细过程)(2022/7/17)
这篇文章详细介绍了Vue的生命周期和各个阶段的钩子函数,包括`beforeCreate`、`created`、`beforeMount`、`mounted`、`beforeUpdate`、`updated`、`beforeDestroy`和`destroyed`。文章通过图解、方法说明、代码实例和测试效果,阐述了每个钩子函数的作用和使用场景,帮助读者深入理解Vue实例从创建到销毁的整个过程。
Vue学习之--------Vue生命周期beforeCreate、created、beforeMount、mounted、beforeDestroy 。。。(图解详细过程)(2022/7/17)
|
网络协议 应用服务中间件 nginx
Nginx的http块sendfile,keepalive_timeout的配置指令说明
Nginx的http块sendfile,keepalive_timeout的配置指令说明
|
Kubernetes 网络协议 Java
Seata常见问题之全局事务处理中的本地会话过多 seata1.7报错如何解决
Seata 是一个开源的分布式事务解决方案,旨在提供高效且简单的事务协调机制,以解决微服务架构下跨服务调用(分布式场景)的一致性问题。以下是Seata常见问题的一个合集
437 0
|
云安全 运维 安全
带你读《从基础到应用云上安全航行指南》——云安全专家教你如何实现一体化、自动化的云安全审计,运营闭环(1)
带你读《从基础到应用云上安全航行指南》——云安全专家教你如何实现一体化、自动化的云安全审计,运营闭环(1)
452 1
|
运维 负载均衡 安全
Apache Doris 极简运维之BE扩缩容(1)
Apache Doris 极简运维之BE扩缩容(1)
668 0
|
SQL 分布式计算 大数据
大数据问题排查系列 - 因HIVE 中元数据与HDFS中实际的数据不一致引起的问题的修复
大数据问题排查系列 - 因HIVE 中元数据与HDFS中实际的数据不一致引起的问题的修复

热门文章

最新文章