实时数仓之Flink维表关联难点解决方案

1、维表关联的典型场景和考量标准

1.1、维表关联的典型场景

在实时数仓中,我们经常需要做维表关联,但是用户维表一般在业务数据库中,业务方是不允许大数据部门直接到业务数据库进行维表关联,因为这会影响线上业务。此时我们需要将用户维表采集到大数据平台,然后事实表就可以直接跟维表进行关联,从而生成事实宽表,具体场景如下图所示。
维度表关联
在生产环境中,我们通过数据采集平台将用户维表采集到大数据平台,然后事实表跟用户维表直接关联就可以了吗?

答案,是不行的。因为在生产环境中,我们还需要考虑如下问题:

  • (1)高流量的情况下数据库是否扛得住。
  • (2)能不能预加载维表数据。
  • (3)预加载数据更新了怎么办。
  • (4)引入缓存是不是更好。
  • (5)引入缓存能不能及时更新。
  • (6)维表数据特别大又怎么搞。

1.2、维表关联的考量标准

总体来说,维表关联有三种基础的方式,分别为实时lookup数据库关联、预加载维表关联和维表变更日志关联。对于不同的关联方式,我们该如何选择呢?我们有哪些考量和选择的依据呢?我们主要通过以下指标来进行衡量。
考量标准
上面三种关联方式不存在绝对的好坏,我们考虑的是针对不同业务场景,在各种指标上进行权衡取舍。

2、维表关联方式

2.1、实时lookup数据库关联

(1)定义
 所谓实时lookup数据库关联,就是在用户自定义函数中通过关联字段直接访问数据库实现关联的方式。
(2)特点
 开发量非常小,数据库压力随着流量增长会越来也大,只能基于ProcessingTime做关联(哪怕Flink设置的基于EventTime),如果数据有延迟或者重放,会得到不一致的结果。

实时lookup数据

(3)细分
 实时lookup数据库关联还可以再细分为三种方式:同步lookup数据库关联、异步lookup数据库关联和带缓存的数据库lookup关联。
1)同步lookup数据库关联
 同步实时数据库lookup关联实现最简单,只需要在一个 RichMapFunction或者 RichFlat-MapFunction中访问数据库,处理好关联逻辑后将结果数据输出即可。

同步lookup数据库关联
优点:

  • 实现简单
  • 无需额外内存
  • 维表更新立马可以实时使用

缺点:

  • 数据库负载高(1条数据查询数据库1次)
  • Task实例同步阻塞,影响吞吐
  • 只能基于ProcessingTime关联,结果不确定
  • 可扩展性差(数据库->分布式数据库)

适合场景:流量低的作业,且维表更新实时性要求不高/维表更新频率低的场景

2)异步数据库关联

异步实时数据库lookup关联需要借助AsyncIO来异步访问维表数据。AsyncIO可以充分利用数据库提供的异步client库并发处理lookup请求,提高task并行实例的吞吐量。AsyncIO提供lookup结果的有序和无序输出,由用户自己选择是否保证event的顺序。
异步数据库关联
优点:

  • 实现较为简单,大部分的逻辑都由 Flink AsyncIO API 封装
  • 吞吐量相对同步lookup提高了

缺点:

  • 有序输出模式下的 AsyncIO 会需要缓存数据,且这些数据会被写入 checkpoint,内存占用会高一些
  • 数据库负载高
  • 只能基于ProcessingTime关联,结果不确定

适合场景:流量不大的作业,且维表更新实时性要求不高/维表更新频率低的场景

3)带缓存的lookup数据库关联

同步和异步lookup方式的通病是数据库负载高(相同维表数据多次lookup还是要走数据库)为了解决这个问题,可引入缓存来减少直接对数据库的请求。而且缓存不需要通过 checkpoint 机制持久化,所以采用本地缓存,例如Guava Cache可以比较轻松的实现。
带缓存的lookup数据库关联
优点:

  • 一定程度降低了数据库压力(跟命中率有关)

缺点:

  • 冷启动时加载数据数据库压力不小
  • 占用额外的内存

3、维表关联方式

3.1、预加载维表关联

(1)定义
 相对于实时lookup数据库关联每条数据都要请求数据库(带缓存时请求略有减少),预加载维表关联是在作业启动时就把维表加载到内存中,不过如果没有命中数据就关联不上了。
(2)细分
 预加载维表关联还可以再细分为四种方式:启动时预加载维表、启动时预加载分区维表、启动时预加载维表+定时刷新和启动时预加载维表+定时lookup数据库。
1)启动时预加载维表

启动时预加载维表实现比较简单,作业初始化时,在用户函数的open方法中读取数据库的维表数据放到内存中,且缓存的维表数据不作为State,每次重启时open方法都被再次执行,从而加载新的维表数据。
启动时预加载维表
优点:

  • 运行期数据库无压力

缺点:

  • 启动时加载维表,短期数据库压力很大
  • 占用额外的内存
  • 维表数据不能实时更新
  • 横向扩展性差

适合场景:适合维表较小,且维表更新实时性要求不高/维表更新频率低的场景,例如IP库、用户信息表

2)启动时预加载分区维表

如果维表很大,每个subtask(task并行实例)都加载全量维表数据会耗费太多内存。因此可以按照业务数据相同的分区规则加载对应的分区维表数据即可。注意这里不要用keyBy(hash的),一定要自定义分区。例如业务数据按照user_id划分为:subtask1(0-499),subtask2(500-100)…,那么在open方法中要根据subtask的id和并行度来计算当前subtask应该记载的维表数据。
启动时预加载分区维表
优点:

  • 运行期数据库无压力
  • 横向扩展性好

缺点:

  • 启动时加载维表,短期数据库压力很大
  • 占用额外的内存
  • 维表数据不能实时更新
  • 设计和维护分区复杂度高
  • 存在关联不上的问题

适合场景:适合维表大,且维表更新实时性要求不高/维表更新频率低的场景

3)启动时预加载维表+定时刷新(亦可分区)

启动时加载维表有两个主要限制:1、维表大小限制(分区解决);2、维表数据不能更新限制;启动时预加载维表+定时刷新就是为了解决后面那个限制。定时刷新可以采用Flink ProcessFucntion 提供的 Timer 或者直接在open方法中初始化一个额外线程(池)来做,区别是Timer 要求KeyedStream(Data-Stream#partitionCustom 并不会返回一个 KeyedStream),所以open方法中额外线程处理刷新是个好办法。
启动时预加载维表+定时刷新
优点:

  • 运行期数据库大部分时间无压力
  • 缓解了维表数据不能实时更新的问题

缺点:

  • 启动时加载维表,短期数据库压力很大
  • 定时刷新时短时间数据库压力大
  • 占用额外的内存
  • 存在关联不上的问题

适合场景:维表大小都可以,但维表更新实时性要求不是特别高/维表更新频率较低的场景,满足大部分维表关联业务

4)启动时预加载维表+实时lookup

其实就是将启动预加载维表和实时look两种方式混合使用,将预加载的维表作为缓存给实时lookup使用,未命中则到数据库里查找。
启动时预加载维表+实时lookup
优点:

  • 解决关联不上数据的问题

缺点:

  • 启动时加载维表,短期数据库压力很大
  • 定时刷新时短时间数据库压力大(如果启用)
  • 占用额外的内存

适合场景:适合流量低,且维表更新实时性要求不高/维表更新频率低的场景

二者结合时,注意事项:

  • lookup可以同步也可以异步
  • 启动时预加载可以分区也可以不分区
  • 启动时预加载可以定时刷新可也以不刷新
  • 具体根据自己的实际要求来

4、维表关联方式

4.1、维表变更日志关联

(1)定义
 前面两种关联方式,是1个流和一个静态表的关联,维表变更日志关联是把维表changelog放到数据流中,然后两个流做join。所谓变更日志类似于MySQL的binlog,通常由维表数据库端将日志push到消息队列(例如Kafka)。

 我们称业务数据流为main stream,称维表变更数据流为dimchange stream。

 因为维表的变更日志是带时间戳的,因此我们能都知道同一条维表数据在不同时刻的状态。
(2)细分
 维表变更日志关联还可以再细分为三种方式:Processing Time 维表变更日志关联、Event Time 维表变更日志关联和Temporal Table Join。
1)Processing Time 维表变更日志关联

基于ProcessTime做关联,可以利用keyBy 将两个流中关联字段相同的数据划分到KeyedCoProcessFunction的同一分区,然后用MapState把维表数据保存下来。在业务数据流的一条记录进到函数时,到 State 中查找有无符合条件的 join 对象,若有则关联输出结果,若无则根据 join 的类型决定是直接丢弃还是与空值关联。这里要注意的是,State 的大小要尽量控制好。首先是只保存每个 key 最新的维度数据值,其次是要给 State 设置好 TTL,让 Flink 可以自动清理。
Processing Time 维表变更日志关联
优点:

  • 无数据库压力
  • 吞吐高
  • 维表实时性高
  • 横向扩展性好

缺点:

  • 实现复杂
  • 占用额外资源(建议State采用 RocksDB StateBack-end,将大部分的维表数据存在磁盘而不是内存中)
  • 数据准确性一般,对于两边数据延迟要求高,一流晚到,有可能关联到未来时间的维表数据

适合场景:对维表的变更实时性要求比较高的场景,但数准确性要求不太高的场景

2)Event Time 维表变更日志关联

跟ProcessTime维表变更日志关联基本一样,不同的是维表变更日志会保存多个时间版本,当业务数据到来时,根绝他的EventTime找到当时的维表数据跟它关联,而不是总用最新数据,低延时的同时又能大大提高准确性。因为State没有提供基于EventTime的TTL,需要自己设计和时间过期的State的清理策略(例如一个Event Time Timer,定时器不要太多,太多影响性能),也可以根据版本数来控制清理逻辑,比如保存5个版本,当新的维表变更数据到来时,判断是否超过了5个版本,超过了就把最老的版本清理掉。
Event Time 维表变更日志关联
优点:

  • 无数据库压力
  • 吞吐高
  • 维表实时性高
  • 横向扩展性好
  • 数据准确性高

缺点:

  • 实现复杂
  • 占用额外资源(建议State采用 RocksDB StateBack-end,将大部分的维表数据存在磁盘而不是内存中)
  • 对于业务数据延迟有要求,维表变更数据不能延迟
3)Temporal Table Join

Temporal Table Join 是 Flink SQL/Table API 原生支持的,它对两个数据流的输入都进行了缓存,因此比基于 Event Time 的维表变更日志关联,它可以容忍任意数据流的延迟,数据准确性更高。

Temporal Table Join 在 SQL/Table API 使用时是十分简单的,但如果想在 DataStream API 中使用,则需要自己实现对应的逻辑。

总体思路是使用一个 KeyedCoProcessFunction,将 dimchange 数据流以时间版本为 key 保存在 MapState 中(与基于 Event Time 的维表变更日志关联相同),再将业务数据流和输出结果也用 State 缓存起来(同样以 Event Time 为 key),一直等到 Watermark 提升到它们对应的 Event Time,才把结果输出和将两个数据流的输入清理掉。

建议不要自己实现,乖乖的用Flink SQL/Table API。
Temporal Table Join
优点:

  • 无数据库压力
  • 吞吐高
  • 维表实时性高
  • 横向扩展性好
  • 数据准确性很高

缺点:

  • 自己实现特别复杂(建议用Flink SQL/Table API )
  • 占用额外资源

适合场景:实现方式最复杂,准确性最好,适合数据准确性要求高且要求容忍一定延迟(分钟级)的业务

结合flink增量检查点理解

5、总结

利用Flink实现实时数仓,实现维表关联的方式非常多,既可以实时lookup数据库关联,又可以预加载维表关联,还可以维表变更日志关联。具体选择哪种方式实现,还需要结合前面具体的指标来衡量,并根据业务需求来选择最合适的实现方式。

  • 13
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
要想在百度八亿网页的数据海洋中找到你所要的信息, 人工方式需要1200 多人年,而百度搜索技术不到1 秒钟。人 们被数据淹没,却渴望知识。商务智能技术已成为当今企业 获取竞争优势的源泉之一。商务智能通常被理解为将企业中 现有的数据转化为知识,帮助企业做出明智决策的IT工具集。 其中数据仓库、OLAP和数据挖掘技术是商务智能的重要组成 部分。商务智能的关键在于如何从众多来自不同企业运作系 统的数据中,提取有用数据,进行清理以保证数据的正确性, 然后经过抽取、转换、装载合并到一个企业级的数据仓库里, 从而得到企业数据的一个全局视图,并在此基础上利用适当 的查询分析、数据挖掘、OLAP等技术工具对其进行分析处理, 最终将知识呈现给管理者,为管理者的决策过程提供支持。 可见,数据仓库技术是商业智能系统的基础,在智能系统开 发过程中,星型模式设计又是数据仓库设计的基本概念之一。 星型模式是由位于中央的事实表和环绕在四周的维度表 组成的,事实表中的每一行与每个维度表的多行建立关系, 查询结果是通过将一个或者多个维度表与事实表结合之后产 生的,因此每一个维度表和事实表都有一个“一对多”的连 接关系,维度表的主键是事实表中的外键。随着企业交易量 的越来越多,星型模式中的事实表数据记录行数会不断增加, 而且交易数据一旦生成历史是不能改变的,即便不得不变动, 如对发现以前的错误数字做修改,这些修改后的数据也会作 为一行新纪录添加到事实表中。与事实表总是不断增加记录 的行数不同,维度表的变化不仅是增加记录的行数,而且据 需求不同维度表属性本身也会发生变化。本文着重讨论数据 仓库维度表的变化类型及其更新技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值