Flink 维表关联方案

news2024/11/28 12:38:02
Flink 维表关联方案
1、Flink DataStream 关联维表
1)概述
1.分类

实时数据库查找关联(Per-Record Reference Data Lookup)

预加载维表关联(Pre-Loading of Reference Data)

维表变更日志关联(Reference Data Change Stream)

根据实现上的优化可以衍生出多种关联方式,且这些优化还可以灵活组合产生不同效果。

2.衡量指标

实现简单性: 设计是否足够简单,易于迭代和维护。

吞吐量: 性能是否足够好。

维表数据的实时性: 维度表的更新是否可以立刻对作业可见。

数据库的负载: 是否对外部数据库造成较大的负载(负载越低分越高)。

内存资源占用: 是否需要大量内存来缓存维表数据(内存占用越少分越高)。

可拓展性: 在更大规模的数据下会不会出现瓶颈。

结果确定性: 在数据延迟或者数据重放情况下,是否可以得到一致的结果。

2)实时数据库查找关联
1.概述

在 DataStream API 用户函数中直接访问数据库进行关联。

开发量最小,会给数据库带来很大压力,而且关联基于 Processing Time,如果数据有延迟或重放,会得到和原来不一致的结果。

2.同步数据库查找关联
a) 概述

在一个 Map 或者 FlatMap 函数中访问数据库,处理好关联逻辑后,将结果数据输出。

在这里插入图片描述

b) 优缺点

优点:

实现简单、不需要额外内存且维表的更新延迟很低。

缺点:

每条数据都需要请求一次数据库,给数据库造成的压力很大;

访问数据库是同步调用,导致 subtak 线程会被阻塞,影响吞吐量;

关联是基于 Processing Time 的,结果并不具有确定性;

瓶颈在数据库端,但实时计算的流量通常远大于普通数据库的设计流量,因此可拓展性比较低。

c) 应用场景

适合流量比较低的作业,但通常不是最好的选择。

3.异步数据库查找关联
a) 概述

通过 AsyncIO 利用数据库提供的异步客户端,AsyncIO 可以并发地处理多个请求,很大程度上减少对 subtask 线程的阻塞。

在这里插入图片描述

b) 优缺点

优点:

实现简单

缺点:

有序输出模式下的 AsyncIO 需要缓存数据,且这些数据会被写入 checkpoint,占用内容资源;

相比数据库查找关联的吞吐量更高,但仍存在数据库负载高和结果不确定的问题。

c) 应用场景

适合流量低的实时计算。

4.带缓存的数据库查找关联
a) 概述

引入一层缓存来减少直接对数据库的请求,缓存一般不需要通过 checkpoint 持久化,可用 WeakHashMap 或 Guava Cache 实现。

在这里插入图片描述

b) 优缺点

优点:

数据库压力小;

缺点:

冷启动时会给数据库造成压力,后续取决于缓存命中率,数据库的压力将得到缓解;

维表的更新不能及时反应到关联操作上,需要根据维度表更新频率和业务对过时维表数据的容忍程度来设计缓存剔除的策略;

c) 应用场景

适合流量比较低,且对维表数据实时性要求不太高或维表更新比较少的业务场景。

3)预加载维表关联
1.概述

相比实时数据库查找在运行期间为每条数据访问一次数据库,预加载维表关联是在作业启动时就将维表读到内存中,在后续运行期间,每条数据都会和内存中的维表进行关联,而不会直接触发对数据库的访问。

与带缓存的实时数据库查找关联相比,区别是后者如果不命中缓存还可以 fallback 到数据库访问,而前者如果不命中则会关联不到数据。

2.启动预加载维表
a) 概述

在作业初始化时,比如用户函数的 open() 方法,直接从数据库将维表拷贝到内存中,维表不需要用 State 保存。

在这里插入图片描述

b) 优缺点

优点:

对数据库的压力只持续很短时间,在运行期间不需要再访问数据库。

缺点:

拷贝整个维表对 TaskManager 内存的要求较高;

运行期间维表数据不能更新。

c) 应用场景

适合于维表较小、变更实时性要求不高的场景,比如根据 ip 库解析国家地区,如果 ip 库有新版本,重启作业即可。

3.启动预加载分区维表
a) 概述

将数据流按字段分区,每个 Subtask 只需要加载对应分区范围的维表数据;

注意:

分区并不是用 keyby 这种通用的 hash 分区,而是需要根据业务数据定制化分区策略,调用 DataStream#partitionCustom;

比如按照 userId 的区间划分,0-999 划分到 subtask 1,1000-1999 划分到 subtask 2,在 open() 方法中,再根据 subtask 的 id 和总并行度来计算应该加载的维表数据范围。

在这里插入图片描述

b) 优缺点

优点:

维表的大小上限可以线性拓展,解决了维表大小受限于单个 TaskManager 内存的问题(取决于所有 TaskManager 的内存总量);

缺点:

设计和维护分区策略较复杂;

c) 应用场景

适合维表较大而变更实时性要求不高的场景,比如用户点击数据关联用户所在地。

4.启动预加载维表并定时刷新
a) 概述

引入定时刷新机制解决维度数据的更新问题;

定时刷新可以通过 Flink ProcessFucntion 提供的 Timer 或者在 open() 初始化一个线程(池)来完成;

在这里插入图片描述

b) 优缺点

优点:

复杂性小,缓解了维度表更新问题;

缺点:

给维表数据库带来更多压力,每次 reload 都是一次请求高峰。

c) 应用场景

适合维表变更实时性要求不高的场景;

取决于定时刷新的频率和数据库的性能,可以满足大部分关联维表的业务。

5.启动预加载维表 + 实时数据库查找
a) 概述

将预加载的维表作为缓存使用,若未命中则 fallback 到数据库查找。

在这里插入图片描述

b) 优缺点

优点:

相比冷启动时未命中缓存导致的多次实时数据库访问,直接拉取整个维表效率更高;

缺点:

可能拉取到不会访问的多余数据;

c) 应用场景

适合流量较低,且对维表数据实时性要求不高或维表更新较少的场景。

4)维表变更日志关联
1.概述

将维表以 changelog 数据流的方式表示,将维表关联转变为两个数据流的 join;

changelog 数据流类似于 MySQL 的 binlog,需要维表数据库端以 push 的方式将日志写到 Kafka 等消息队列中;

changelog 数据流称为 build 流,待关联的主要数据流成为 probe 流,可以获取某个 key 数据变化的时间,在关联中使用 Event Time 或 Processing Time。

2.Processing Time 维表变更日志关联
a) 概述

基于 Processing Time 关联,利用 keyby 将两个数据流中关联字段值相同的数据划分到 KeyedCoProcessFunction 的同一个分区,用 ValueState 或者 MapState 将维表数据保存下来。

在普通数据流的一条记录进到函数时,到 State 中查找有无符合条件的 join 对象,若有则关联输出结果,若无则根据 join 的类型决定是直接丢弃还是与空值关联。

**注意:**State 的大小要控制,首先只保存每个 key 最新的维度数据值,其次要给 State 设置 TTL,让 Flink 可以自动清理。

在这里插入图片描述

b) 优缺点

优点:

不需要直接请求数据库,不会对数据库造成压力;

利用 Flink 的 RocksDB StateBackend,将大部分的维表数据存在磁盘而不是内存中,并不会占用很高的内存;

缺点:

需要使用 changelog 在 Flink 应用端重新构建一个维表,会占用一定的 CPU 和比较多的内存和磁盘资源;

基于 Processing Time 的关联对两个数据流的延迟要求较高,当其中一个数据流出现 lag 时,可能会关联到未来时间点的维表数据。

c) 应用场景

适用于不便直接访问数据的场景(比如维表数据库是业务线上数据库,出于安全和负载的原因不能直接访问)

对维表的变更实时性要求较高的场景(因为数据准确性的关系,一般用 Event Time 关联会更好)

3.Event Time 维表变更日志关联
a) 概述

将维表 changelog 的多个时间版本都记录下来,每当一条记录进来,会找到对应时间版本的维表数据来关联,而不是总用最新版本,因此延迟数据的关联准确性将提高;

目前 State 并没有提供 Event Time 的 TTL,需要设计和实现 State 的清理策略,比如设置一个 Event Time Timer(注意 Timer 太多会导致性能问题),对于单个 key 只保存最近的 10 个版本,当有更新版本的维表数据到达时,要清理掉最老版本的数据。

在这里插入图片描述

**注意:**Event Time 要求 build 数据流的延迟低,否则可能一条数据到达时关联不到对应维表数据或者关联了过时版本的维表数据;

b) 优缺点

优点:

可以确保准确性;

缺点:

多个维表版本导致空间资源要求更大;

c) 应用场景

适合维表变更较多且对变更实时性要求较高的场景;

适合不便直接访问数据库的场景;

4.DataStream 的 Temporal Table Join
a) 概述

对两个数据流的输入都进行缓存,比起基于 Event Time 的维表变更日志关联,可以容忍任意数据流的延迟,数据准确性更好。

实现:

使用 CoProcessFunction,将 build 数据流以时间版本为 key 保存在 MapState 中,再将 probe 数据流和输出结果也用 State 缓存起来(同样以 Event Time 为 key),直到 Watermark 提升到它们对应的 Event Time,才把结果输出和将两个数据流的输入清理掉。

Watermark 触发是用 Event Time Timer 实现,但要注意不要为每条数据都设置一个 Timer,否则 Watermark 提升会触发多个 Timer 导致性能急剧下降。

建议为每个 key 只注册一个 Timer,记录当前未处理的最早的一个 Event Time,并用来注册 Timer,每当 Watermark 触发 Timer 时,检查未处理的最早 Event Time 到当前 Event Time 的所有数据,并将未处理的最早 Event Time 更新为当前时间。

在这里插入图片描述

注意:

如果维表变更太慢,导致 Watermark 提升太慢,会导致 probe 数据流被大量缓存,要确保 build 数据流尽量实时,同时给 Source 设置一个比较短的 idle timeout。

b) 优缺点

优点:

对两边数据流延迟的容忍度较大;

缺点:

会引入一定的输出结果的延迟;

因为吞吐量较大的 probe 数据流也需要缓存,对空间资源的需求较大;

c) 适用场景

适合对数据准确性要求高且可以容忍一定延迟(一般分钟级别)的业务。

2、Flink SQL 实现数据流的 Join
1.Regular Join
a) 概述

Regular Join 和离线 Hive SQL ⼀样,通过条件关联两条流数据输出。

b) 分类
  • Inner Join(Inner Equal Join):流任务中,只有两条流 Join 到才输出,输出 +[L, R]
  • Left Join(Outer Equal Join):流任务中,左流数据到达之后,⽆论有没有 Join 到右流的数据,都会输出(Join 到输出 +[L, R] ,没 Join 到输出 +[L, null] ),如果右流数据到达之后,发现左流之前输出过没有 Join 到的数据,则会发起回撤流,先输出 -[L, null] ,然后输出 +[L, R]
  • Right Join(Outer Equal Join):与 Left Join ⼀样,左表和右表的执⾏逻辑完全相反
  • Full Join(Outer Equal Join):流任务中,左流或者右流的数据到达之后,⽆论有没有 Join 到另外⼀条流的数据,都会输出(对右流来说:Join 到输出 +[L, R] ,没 Join 到输出 +[null, R] ;对左流来说:Join 到输出 +[L, R] ,没 Join 到输出 +[L, null] )。如果⼀条流的数据到达之后,发现另⼀条流之前输出过没有 Join 到的数据,则会发起回撤流(左流数据到达为例:回撤 -[null, R] ,输出+[L, R] ,右流数据到达为例:回撤 -[L, null] ,输出 +[L, R] )
c) 注意

实时 Regular Join 可以不是 等值 join,等值 join 和 ⾮等值 join 区别在于,等值 join 数据 shuffle 策略是 Hash,会按照 Join on 中的等值条件作为 id 发往对应的下游;⾮等值 join 数据 shuffle 策略是 Global,所有数据发往⼀个并发,按照⾮等值条件进⾏关联。

在这里插入图片描述

Join 的流程是左流新来⼀条数据后,会和右流中符合条件的所有数据做 Join,然后输出。

流的上游是⽆限的数据,关联需要 Flink 将两条流的所有数据都存储在 State 中,所以 Flink 任务的 State 会⽆限增⼤,需要为 State 配置合适的 TTL,以防⽌ State 过⼤。

2.Interval Join
a) 概述

Interval Join 可以让⼀条流去 Join 另⼀条流中前后⼀段时间内的数据。

b) 分类
  • Inner Interval Join:流任务中,只有两条流 Join 到(满⾜ Join on 中的条件:两条流的数据在时间区间 + 满⾜其他等值条件)才输出,输出 +[L, R]
  • Left Interval Join:流任务中,左流数据到达之后,如果没有 Join 到右流的数据,就会等待(放在 State 中等),如果右流之后数据到达,发现能和刚刚那条左流数据 Join 到,则会输出 +[L,R] 。事件时间中随着 Watermark 的推进(也⽀持处理时间)。如果发现发现左流 State 中的数据过期了,就把左流中过期的数据从 State 中删除,然后输出 +[L, null] ,如果右流 State 中的数据过期了,就直接从 State 中删除。
  • Right Interval Join:和 Left Interval Join 执⾏逻辑⼀样,只不过左表和右表的执⾏逻辑完全相反。
  • Full Interval Join:流任务中,左流或者右流的数据到达之后,如果没有 Join 到另外⼀条流的数据,就会等待(左流放在左流对应的 State 中等,右流放在右流对应的 State 中等),如果之后另⼀条流数据到达之后,发现能和刚刚那条数据 Join 到,则会输出 +[L, R] 。事件时间中随着 Watermark 的推进(也⽀持处理时间),发现 State 中的数据过期了,就将这些数据从 State 中删除并且输出(左流过期输出+[L, null] ,右流过期输出 -[null, R] )

**Inner Interval Join 和 Outer Interval Join 的区别在于:**随着时间推移的过程中,如果有数据过期了之后,会根据是否是 Outer 将没有 Join 到的数据也给输出。

c) 注意

实时 Interval Join 可以不是 等值 join ,等值 join 和 ⾮等值 join 区别在于,等值 join 数据 shuffle 策略是 Hash,会按照 Join on 中的等值条件作为 id 发往对应的下游;⾮等值 join 数据 shuffle 策略是 Global,所有数据发往⼀个并发,将满⾜条件的数据关联输出。

3.Temporal Join
a) 概述

同离线中的 拉链快照表 ,Flink SQL 中对应的表叫做 Versioned Table ,使⽤⼀个明细表去 join 这个 Versioned Table 的 join 操作叫做 Temporal Join。

Temporal Join 中,Versioned Table 是对同⼀条 key(在 DDL 中以 primary key 标记同⼀个 key)的历史版本(根据时间划分版本)做维护,当有明细表 Join 这个表时,可以根据明细表中的时间版本选择 Versioned Table 对应时间区间内的快照数据进⾏ join。

b) Verisoned Table

Verisoned Table 中存储的数据通常来源于 CDC 或者会发⽣更新的数据,Flink SQL 会为 Versioned Table 维护 Primary Key 下的所有历史时间版本的数据。

c) 注意

事件时间的 Temporal Join ⼀定要给左右两张表都设置 Watermark。

事件时间的 Temporal Join ⼀定要把 Versioned Table 的主键包含在 Join on 的条件中。

4.Lookup Join(维表 Join)
a) 概述

Lookup Join 是维表 Join,实时数仓场景中,实时获取外部缓存。

b) 注意

同⼀条数据关联到的维度数据可能不同;

会发⽣实时的新建及更新的维表应该建⽴起数据延迟的监控,防⽌流表数据先于维表数据到达,关联不到维表数据;

5.Time-Windowed Join

利用窗口给两个输入表设定一个 Join 的时间界限,超出时间范围的数据则对 JOIN 不可见并可以被清理掉;

时间可以是指计算发生的系统时间(即 Processing Time),也可以是指从数据本身的时间字段提取的 Event Time;

如果是 Processing Time,Flink 根据系统时间自动划分 Join 的时间窗口并定时清理数据;如果是 Event Time,Flink 分配 Event Time 窗口并依据 Watermark 来清理数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1356844.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot从配置文件中获取属性的方法

方式一:Value 基本类型属性注入,直接在字段上添加Value("\${xxx.xxx}")即可.注意这里用的是$,而不是#,Value注入的属性,一般其他属性没有关联关系。 配置文件 user:name: Manaphya…

代码随想录算法训练营day6|242.有效的字母异位词、349.两个数组的交集、202.快乐数

哈希表理论基础 建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。 什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时…

C#用StringBuilder高效处理字符串

目录 一、背景 二、使用StringBuilder便捷、高效地操作字符串 三、实例 1.源码 2.生成效果 四、实例中知识点 1.StringBuilder类 一、背景 符串是不可改变的对象,字符串在创建以后,就不会被改变,当使用字符串对象的Replace、split或Re…

提供电商Api接口-100种接口,淘宝,1688,抖音商品详情数据安全,稳定,支持高并发

Java是一种高级编程语言,由Sun Microsystems公司于1995年推出,现在属于Oracle公司开发和维护。Java以平台无关性、面向对象、安全性、可移植性和高性能著称,广泛用于桌面应用程序、嵌入式系统、企业级服务、Android移动应用程序等。 接口是Ja…

JS运行机制、Event Loop

1、JS运行机制 JS最大的特点就是单线程,所以他同一时间只能做一件事情。使单线程不阻塞,就是事件循环。 在JS当中分为两种任务: 同步任务:立即执行的任务,一般放在主线程中(主执行栈)。异步任…

Python消消乐小游戏(PyGame)

文章目录 写在前面喜羊羊与灰太狼PyGame入门消消乐注意事项写在后面 写在前面 本期内容:基于pygame实现喜羊羊与灰太狼版消消乐小游戏 实验环境 python3.11及以上pycharmpygame 安装pygame的命令: pip install -i https://pypi.tuna.tsinghua.edu.c…

前端基础:Vue搞笑白话文(工作之余瞎写)

1、data:{}与data(){return{}}这两个是个什么鬼? vue实例 new Vue({el:#app,data:{name:李四}}) 组件实例 const aaa Vue.extent({data(){return {name:}} }) 为什么Vue实例可以那么写而组件实例就不行了?原因就是因为在底层原理上,组件…

【KingbaseES】实现MySql函数Space

CREATE OR REPLACE FUNCTION SPACE(input_length integer) RETURNS text AS $$ BEGIN RETURN REPEAT( , input_length) AS SPACES; END; $$ LANGUAGE plpgsql;

Windows 下用 C++ 调用 Python

文章目录 Part.I IntroductionChap.I InformationChap.II 预备知识 Part.II 语法Chap.I PyRun_SimpleStringChap.II C / Python 变量之间的相互转换 Part.III 实例Chap.I 文件内容Chap.II 基于 Visual Studio IDEChap.III 基于 cmakeChap.IV 运行结果 Part.IV 可能出现的问题Ch…

从零开始使用Konva,画图并绑定节点。

实战可行,vue3vitets实现 实现电子地图,左侧列表可拖拽绑定 地图可绑定点设备坐标 安装 npm install konva 插件引入 import Konva from konva import Konva from konva import { getImgUrl } from /utils export class konvaManager {public stage…

视频怎么配上音乐?视频软件轻松配乐

视频怎么配上音乐?视频配乐已经成为了一种重要的表达方式。它能够为视频增添情感,营造氛围,让观众更加深入地理解视频的内容。那么,哪些软件可以给视频配上音乐呢?本文将为你介绍几款优秀软件。 一、清爽视频编辑 清爽…

福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!

千里之行,始于足下,若想提高软件编程能力,最最重要的是实践,所谓纸上得来终觉浅,绝知此事要躬行。根据相关【艾宾浩斯遗忘曲线】研究表明,如果不动手实践,记住的东西会很快忘记。 为了便于大家查…

虚幻UE 增强输入-第三人称模板增强输入分析与扩展

本篇是增强输入模块,作为UE5.0新增加的模块。 其展现出来的功能异常地强大! 让我们先来学习学习一下第三人称模板里面的增强输入吧! 文章目录 前言一、增强输入四大概念二、使用步骤1、打开增强输入模块2、添加IA输入动作2、添加IMC输入映射内…

SAFe大规模敏捷企业级实训

课程简介 SAFe – Scaled Agile Framework是目前全球运用最广泛的大规模敏捷框架,也是成长最快、最被认可、最有价值的规模化敏捷框架,目前全球SAFe认证专业人士已达80万人,福布斯100强的70%都在实施SAFe。本课程是一个2天的 SAFe权威培训课…

线程的深入学习(二)

前言 上一篇讲了线程池的相关知识,这篇文章主要讲解一个 1.并发工具类如CountDownLatch、CyclicBarrier等。 2.线程安全和并发集合: 3.学习如何使用Java提供的线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList等。 并发工具类 …

java练习题之String方法运用

应用知识点:​​​​​​String类 1:(String 类)仔细阅读以下代码段: String s "hello"; String t"hello"; char[] c {h,e,l,l,o}; 2:下列选项输出结果为false 的语句是() System.out.println( s.euqals( t…

线段树基础(下)

线段树二分 对序列进行二分的操作,可能使用线段树二分进行优化。 一些序列上最左/最右位置问题可以二分解决,同时需要使用线段树进行查询。时间复杂度通常是 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n),可以尝试使用线段树二分的技巧将其优…

机器学习(四) -- 模型评估(2)

系列文章目录 机器学习(一) -- 概述 机器学习(二) -- 数据预处理(1-3) 机器学习(三) -- 特征工程(1-2) 机器学习(四) -- 模型评估…

B端产品经理学习-对用户进行需求挖掘

目录: 用户需求挖掘的方法 举例:汽车销售系统的用户访谈-前期准备 用户调研提纲 预约用户做访谈 用户访谈注意点 我们对于干系人做完调研之后需要对用户进行调研;在C端产品常见的用户调研方式外,对B端产品仍然适用的 用户需…

6.1810: Operating System Engineering 2023 <Lab6: Multithreading>

一、本节任务 二、要点 2.1 锁(Locking) 在多 CPU 或者单 CPU 多线程并发的场景中,对临界资源(或者说共享资源)的访问如果不加以限制,可能会引发一些严重的问题,比如当两个线程同时对一个共享…