Flink架构浅析:流表二象性

128 阅读5分钟

背景

很对大数据相关的产品,都对用户或者分析师提供了SQL API,比如Hive,Spark,Flink等,SQL作为传统关系型数据库的查询语言,是应用在批查询场景的,Hive和Spark本质是都是批量的计算模式。但是Flink是纯流式的计算模式,流与批在数据集和计算过程上有很大的区别,如下:

  • 批处理场景的特点:有限数据集,一次处理返回一个计算结果就接触
  • 流处理场景的特点:无限数据集,一次处理不断修正计算结果,处理永不结束

从上图可以看出,为啥纯流式模式的Apace Flink为啥能为用户提供SQL API呢

DataStream上的关系查询

关系型SQL和stream process对比如下:

SQL

Stream Processing

有限元组

无限元组

完整数据集上的查询

无法基于所有数据查询

查询会结束

查询不会结束

物化试图(Materialized View)的特性被定义为一条SQL查询,其会缓存查询结果,当所查询的表(基表)被修改时,缓存的结果即将过期。

即时视图维护(Eager View Maintenance)会更新**Materialized View,**当基表被更新时,会立刻更新Materialized View中缓存的结果。

Eager View MaintenanceSQL Querystreams上的关系如下。

  • 数据库表是INSERT、UPDATE、DELETEDML语句流的结果,被流称为changelog stream
  • Materialized View被定义为一条SQL查询。为更新View,查询需要不断处理changelog stream
  • Materialized Viewstreaming SQL查询结果。

动态表 & 连续查询

动态表式Flink流上Table API & SQL的核心概念,其随时间动态变化:

  • 查询动态表会产生一个连续查询
  • 连续查询永不停止,会产生一个动态表;
  • 当所查询的动态表发生变化时,查询会更新结果动态表。

连续查询的结果等同在输入表的快照上以批处理模式执行相同查询的结果

流、动态表、连续查询的关系如下所示:

  • Stream 会转化为动态表
  • 在动态表上进行连续查询,会产生新的动态表
  • 动态表会转化为Stream

流上定义表

为在流上使用关系型查询,流需要转化为表,流的每个记录被解释为结果表(动态表)上的INSERT修改,我们从一个只有INSERT的changelog流中构建表,如下图所示,点击事件流被转为表,表会随着点击事件记录的插入而不断增长。

连续查询

连续查询作用于动态表并会产生动态表;连续查询不会终止并会根据其输入表(动态表)上的更新结果表(动态表).

下面显示在点击事件流上定义的clicks表上显示两个查询示例。

先看简单的GROUP-BY COUNT 查询,基于user字段对clicks表进行分组,并统计访问URL的数量。

当当查询开始时,clicks表为空;当第一行插入到clicks表中时,查询开始计算结果表(动态表),如[Mary, ./home]插入后,结果表包含一行结果[Mary, 1];当插入第二行[Bob, ./cart]时,查询会更新结果表并插入新记录[Bob, 1]。第三行[Mary, ./prod=id=1]插入时,查询会更新结果表中的[Mary, 1]记录,将其更新为[Mary, 2]。最后一行[Liz, 1]插入clicks表后,也会更新到结果表(插入新记录)。

第二个查询与第一个查询类似,除了用户属性之外,还在小时窗口对clicks表进行分组,然后对URL进行计数(基于时间的计算,如窗口基于特殊的时间属性)。

每个小时查询会计算结果并更新结果表。在cTime12:00:00 - 12:59:59之间,clicks表存在四条记录,对应的查询计算出两条结果;下个时间窗口(13:00:00 - 13:59:59),clicks表中存在三条记录,对应的查询计算出两条结果添加值结果表中;当记录插入至clicks表中后,结果表也会被动态更新。

更新和追加查询

上述两个查询虽然有些类似(均计算统计聚合分组),但两者也有显著不同:第一个查询会更新结果表的结果,如定义在结果表上的changelog流包含INSERT和UPDATE;第二个查询仅仅往结果表中添加记录,如定义结果表上的changelog流只包含INSERT。

一个查询是产生一个只追加的表还是一个更新的表有一些含义:

  • 产生更新更改的查询通常需要state状态进行保存中间值
  • 将append-only的表转换为流与将已更新的表转化为流是不同的

表到流的转换

在将动态表转换为流或将其写入外部系统时,需要对这些进行更改编码。Flink 的Table AP和SQL 支持三种方式编码一个动态表的变化:

模式

INSERT

UPDATE

DELETE

Append

支持

不支持

不支持

Upsert

支持

支持

支持

Retract

支持

支持

支持

  • Append-only 流: 仅通过 INSERT 操作修改的动态表可以通过输出插入的行转换为流。

  • Retract 流: retract 流包含两种类型的 message:

    add messages

    retract messages

    。通过将INSERT 操作编码为 add message、将 DELETE 操作编码为 retract message、将 UPDATE 操作编码为更新(先前)行的 retract message 和更新(新)行的 add message,将动态表转换为 retract 流。下图显示了将动态表转换为 retract 流的过程。

  • Upsert 流: upsert 流包含两种类型的 message:

    upsert messages

    delete messages

    。转换为 upsert 流的动态表需要(可能是组合的)唯一键。通过将 INSERTUPDATE 操作编码为 upsert message,将 DELETE 操作编码为 delete message ,将具有唯一键的动态表转换为流。消费流的算子需要知道唯一键的属性,以便正确地应用 message。与 retract 流的主要区别在于 UPDATE 操作是用单个 message 编码的,因此效率更高。下图显示了将动态表转换为 upsert 流的过程。


参考资料:developer.aliyun.com/article/667…