|--------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| | 博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,京东购书链接:https://item.jd.com/12677623.html,扫描左侧二维码进入京东手机购书页面。 |
尽管我们在此前的多篇文章中介绍过动态表的概念,但这个概念确实有一些抽象,伴随着学习的地深入,也会有会新的领悟,本文再次去动态表和表流二象性做一些梳理。此前对动态表的介绍可参考《Flink 动态表 (Dynamic Table) 解读》和《Flink 实时数仓关键技术解读:Upsert Kafka 和 动态表》两篇文章。
1. 回顾
[ 官方文档 ] 中绘制过这样一张描述动态表和连续查询的图:
- 将流转换为动态表。
- 在动态表上计算一个连续查询,生成一个新的动态表。
- 生成的动态表被转换回流。
注意:动态表首先是一个逻辑概念。在查询执行期间不一定(完全)物化动态表;此外,要注意的一点是:"状态"(State)是维迟在持续查询上的,不是动态表上,这一点不搞错,是查询本身的内容(SQL)决定了会维持什么样的"转态"!
但是,从"表流一体"或"流表二象性"的角度看,其实改为下面这样会更准确一些,至于为什么,我们在下一节介绍完"表流二象性"后就会理解。
2. 流表二象性
对于"动态表"在使用时是一张"表",实际运行的形态却是一条"流"这种情形被概括为"表流二象性",下面的动图非常好的解释了流表之间的关系:
在这张动图中,我们可以形象而准确地看到:
-
下侧的 Stream 和 中间 Table 的 "联动" 很好地诠释了 "表流一体" 或 "表流二象性",如果非要再细致一点解释的话,此时中间 Table 的输出其实是 Flink Sql Client 在 Table 模式下的输出(自动刷新表的当前转态)
-
伴随流上数据不停地输入,表本身也是在不断变化的,且这种变化是由输入数据直接触发的,是一种固有的动态能力,与批处理中的轮训完全是两回事,这大概就是"动态表"叫法的来历
-
上侧的 Stream 记录的是表自身的 changelog,也就是交给下游或物化时的 "输出"(也是一条流)
下图是另一张解释 "表流一体" 或 "表流二象性"的动图,相对上一张图,它用棋盘举例更加形象:
不过,这张图并没有上一张图严谨,主要的问题在于:没有说明左侧的"操作记录"流是右侧棋局变化的"因"还是"果",如果是"因",那左侧就是输入的数据流,右侧是对应的动态表,这时相当于上一张图中的 "Stream" 和 "Tabel" 两条线;如果是"果",那左侧就是输出的数据流,右侧依然是动态表,这时相当于上一张图中的 "Stream(changelog)" 和 "Tabel" 两条线。
3. 从代码层面重新理解
现在,我们得从实际代码层面把动态表的概念打通,核心问题就是:动态表的 DDL 定义了什么?持续查询又做了什么?这方面,有如下重要的结论:
所谓"动态表的 DDL"这种叫法其实是有问题的,因为动态表就是流上的结构化数据,没有 DDL 这一说,并且,也并不是所有的动态表都和一个 DDL 相对应,考虑一个只有 SELECT 没有 INSERT INTO 的持续查询,SELECT 的结果集肯定也是一张动态表,对应一个转换后的流,但它是没有对应的 DDL 的。Flink SQL 的 DDL 定义的其实是流的 Source 或 Sink 的连接方式、数据结构、传输格式。只是绝大多数的流都是从一个 Source Table 到一个复杂的持续查询(INSERT INTO ... SELECT ...)最后写入一个 Sink Table,会让人习惯性地把 DDL 当作了 动态表 的定义,这一点一定要注意其中细微差别!
3.1 动态表定义了什么?
动态表的 DDL 定义了三项核心要素:
- 数据结构
- 数据源(connector)
- 传输格式(format)
有了这些信息,Flink 就可以:
- 当动态表是 Source 时:从源头获得数据 -> 按指定的数据结构封装成指定的格式传输 -> 成为数据流 / 表现为一张表(动态表)
- 当动态表是 Sink时:实时读取动态表(动态表的 changelog 流) -> 按指定的数据结构封装成指定的格式传输 -> 写入目标数据源
3.2 持续查询又做了什么?
从 ETL 的角度看,持续查询完成了最核心的 ETL 逻辑,从整个流式处理管道的角度看,是持续查询驱动了整个 Pipeline 运转,只有动态表的 DDL,不会有任何流或对应的动态表产生,只有当一个持续查询启动时,整条流式链路才会创建并运转起来。下图能更好地体现"流","动态表","持续查询"三者之间的关系:
参考资料
https://www.confluent.io/blog/kafka-streams-tables-part-1-event-streaming/#stream-table-duality