使用布尔代数解耦业务

发布时间 2023-05-24 20:35:43作者: 蝌蝌

业务背景

有这样一个场景,数据供应商定期提供一次海量的数据,把这些数据存储到 Hadoop hive 中去,但是这些数据和我们系统是不通用的,需要先进行分析以便于我们的系统能够识别这些数据,具体的分析过程省略,最后生成一个 mapping 关系数据,存储着两边的标志 key 和数据的生命周期。

目前的系统设计分为两个job,job 1 解析数据生成 mapping 关系数据存储到关系型数据库 SQL Server 中;job 2 存储这些数据到 Hadoop hive 中。

问题介绍

job 2 保存这些数据的时候需要根据 job 1 的 mapping 关系数据进行分类保存。当 API 查询使用 Hadoop hive 里面的数据的时候,需要再一次根据 mapping 关系数据里面的生命周期提取对应的数据。

job 1 的结果被严重依赖,而且供应商提供的数据本身也存在小概率的错误,一旦出现问题,导致整个业务崩溃,或者最终的结果出错。

解决问题

这种情况下,亟需将两个 job 解耦,job2 只需要专心存储数据,不要再依赖 mapping 关系数据。
对 job1 升级改造,分析数据的时候不仅仅解析出 mapping 关系数据,同时也要知道对应的数据是否存在且符合生命周期,如果不符合,那么要回溯历史数据,提供最近一次符合条件的数据。

解决方案

对于海量的数据,不适合全部存储在关系型数据库中,用布尔值去表示一个数值是否存在即可,数据文件就变成了一行行的布尔值。

行数 数值1 数值2 ... 数值N
1 1 0 1 1
2 0 1 0 0
... 0 1 0 0
M 0 1 0 0

数值 N 目前最大还不超过 5000 个,那么一行数据最多 5000/8 = 625 byte 便可以存下了,SQL Server 中一行数据一般不超过 4 KB,所以余量是非常充足的,即使 N 以后增长到 32000 个也不影响性能。

行数 M,目前一次最大是 1,000,000,那么这一次的整个索引大小是
1,000,000 * 625 / 1024 / 1024 = 596 MB.
完全可以接受。

PK 是 mapping 关系中的标志 key,数据的主键。
Time 是数据的生命周期,这里简化成一个时间。
DataIndex 一行布尔值相当于是这行数据的索引,这里要把 布尔值 顺序颠倒过来,数值N在左边,数值1在右边,便于以后拓展长度。

PK Time DataIndex
1 20230405 11...01
2 20230112 00...01
... 20230102 00...01
M 20230119 00...01

那么现在想要知道某个时间下某个或者某些数值,就可以用 布尔运算 从索引中迅速定位到了。
例如 q1:20230112 的 factor 2
查询语句

select * from table a
where a.Time <= '20230112' and (a.DataIndex & 0x10) == 0x10

通过这个索引的查找就可以精确定位到某个数值存储在哪个 pk 和 time 那里了,那么只需要简单的从 Hadoop hive 中对应的位置取数据即可。

因此实现了 job1 和 job2 的解耦,job 2 再也不用担心 mapping 关系数据是否准确,生命周期如何处理这些问题了,它只需要做好它擅长的存储工作即可。