使用布尔代数解耦业务
业务背景
有这样一个场景,数据供应商定期提供一次海量的数据,把这些数据存储到 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 关系数据是否准确,生命周期如何处理这些问题了,它只需要做好它擅长的存储工作即可。