线上数据问题排查案例分享 - 因为 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 文件的完整性;
- 相干 JIRA
[https://issues.apache.org/jir…
](https://issues.apache.org/jir…)