关于后端:Flink-Table-Store-03-构建流式数仓最佳实践

47次阅读

共计 5302 个字符,预计需要花费 14 分钟才能阅读完成。

摘要:本文整顿自阿里巴巴高级技术专家,Apache Flink PMC 李劲松(之信),在 FFA 2022 实时湖仓的分享。本篇内容次要分为四个局部:

  1. 挑战:Streaming DW 面临的难题
  2. 案例:Flink+FTS 典型场景案例
  3. V0.3:FTSV0.3 有什么能力来帮忙上述场景
  4. 总结:回顾和我的项目信息

点击查看直播回放和演讲 PPT

一、挑战:Streaming DW 面临的难题

首先,讲一讲 Streaming Data Warehouse 面临的难题。Streaming Data Warehouse 是什么呢?

如上图所示,数据源从 MySQL 或 Logs,通过 Flink CDC 或 Flink Streaming,把数据摄入到仓里。这个仓能够分 ODS 层、DWD 层、DWS 层。每一层的存储写的是 Flink Table Store。

这样一个看起来跟离线数仓类似的 Pipeline,它的特点是全链路实时流动。通过 Flink Streaming 作业串联,在全链路流动的同时,数据积淀到了 Flink Table Store 的存储上。这个存储不再是之前的 Kafka,只能留,不能查。

这个架构的典型特点是全链路实时可流动,全链路实时可查。这个存储里的数据,能被各生态的计算引擎查问剖析。积淀数据之后,每一份数据在 ODS 层、DWD 层、DWS 层,能够分层复用,缩小大量存储和计算的节约。

尽管这个架构了解起来十分的简略,但却不容易实现。咱们来简略剖析一下,存储在这个架构中的作用。存储次要有三个作用:

  1. 音讯队列。因为全链路是流起来的,存储自身要做一个音讯队列,可流写、可流读,须要有肯定的程序性。
  2. 积淀数据。积淀的历史数据须要要面向各生态计算引擎,做到可剖析。积淀数据之后,这部分数据应该被治理。
  3. 存储须要加强流计算,让流计算变得更简略,解决流计算的难题。

如上图所示,存储在这个架构里施展了多少作用,又有多少挑战呢?

  1. 全增量一体摄入。在一个流作业中,全量数据读完之后,无缝切换到增量数据再读,数据和流作业一起进入下一个环节。存储在这里遇到的挑战是,既然有数据全增量一体摄入,阐明数据量很大,数据乱序很重大。存储能不能撑住?能不能用高吞吐来撑持全增量一体摄入?
  2. 音讯队列的流读。存储自身作为音讯队列须要流写、流读,非常灵活。存储能不能提供全增量一体的流读?能不能指定 timestamp 从历史开始读增量?
  3. Changelog 的流读。图中的第三局部,Flink 基于 State 的计算严格依赖 Changelog。如果 Changelog 谬误,Flink 计算将呈现各种各样正确性的问题。当用户输出到存储后,从存储流读的 log 是否精确?变更日志是否残缺?这些问题是十分要害。
  4. 可流 Join 的存储。目前,流计算中 Join 是十分头疼的问题。不光是流计算自身在存储和流计算联合,存储自身也应该在流 Join 上施展较大的作用。
  5. 丰盛生态的查问。存储跟计算不一样,存储要有比拟好的生态。因为不能假如计算能解决所有问题,所以存储须要被各种引擎查问。它必须有一个较好的生态。

二、案例:Flink+FTS 典型场景案例

如上图所示,在业务上这个案例是一个销售大宽表。它的业务逻辑是上图中的的四张表,我须要把订单表、退货表、顾客表和退货起因表,打宽到一起,不便各种引擎查问。

接着,增量数据写到 Clickhouse 或 ElasticSeach 中。Trino + FTS 的查问能够满足不少场景,然而有些查问的要求更高,它的依赖面向 OLAP 面向索引。

因而,四个多表连贯到一起,打成大宽表,而后写到一张表当中,并且增量数据写到上游的引擎中。在流计算中,如何做到 realtime 的打宽?这是一个比拟难的问题。

咱们先来剖析下此例子中的各个表,因为订单表和退货表是同主键的,它们都有订单 ID,订单表中也有顾客 ID,它能够和顾客表进行 Join,获取一些维表信息。其次,顾客表始终在变动,顾客能够批改本人的信息。最初,退货起因表是不可变的。因为退货就起因,个别是不能被编辑的。

对于业务来说,有一个非常简单的思路,就是把这四张表 Join 一下,而后写到存储当中。然而这种办法的代价十分高,存储会成倍增加,老本十分高。

面对实在的业务,咱们想让业务实现更多的离线计算、离线 Pipeline 变的实时化。但业务切换到实时化后,实时计算的老本是离线计算的数十倍。

所以针对此案例,如何应用 Flink Table Store 呢?

咱们首先创立 DWD 的大宽表。订单 ID 是主键,有些字段来自订单表,有些字段来自退货表,还有一些字段来自顾客表和退货起因表。

通过定义,它申明 merge-engine=partial-update,changelog-producer=full-compaction,剩下的两个是相干的参数。

通过 Flink Table Store 的 partial-update 的能力,使得雷同的两张表同时写到一个大宽表当中,更新各自的字段,互不影响。而且因为配置了 changelog-producer,所以在 Compaction 时会产生正确的宽表日志,上游的流读能够读到最新合并后的数据。

接下来,对于顾客表和退货起因表,怎么打宽?

退货起因表有一个特点是,它的表条数较少,退货表不可更改。所以它比拟适宜应用 Flink Table Store 作为 Lookup Join 表。进行 Lookup Join,Flink Table Store 会保护一些磁盘 cache。用户不必放心数据量太大,导致 OOM。

联合应用 Flink 1.16 Retry Lookup,保障退货表肯定能 Join 到 reason 表。即便 reason 表更新较慢,它也能保障 Join 上。通过 Flink Retry Lookup 的形式,老本比拟低。

接下来,讲一讲顾客表。顾客表跟退货表不一样,顾客表的数据量较大,它须要驱动更新。联合 Flink Table Store,心愿能提供一个新的思路。

顾客表和订单表 Join,它只有订单 ID 和顾客 ID 的映射关系,以及顾客表的其它字段。顾客表没有订单表的主键。所以这里的需要是,咱们须要给顾客表拿到订单表的主键,也就是订单 ID。

咱们能够启动一个双流 Join 来使得顾客表拿到订单 ID,这个双流 Join 的 State 存储老本是 订单 ID 和顾客 ID 的映射关系,以及顾客表的内容,咱们能够认为这个 State 不太大,它的老本可控,毕竟它没有保留宏大的订单表。

通过 Join 之后,这个顾客表就能拿到订单 ID,能够进行上述基于 FTS 的 Partial Update。

实现上游四张表 Partial Update 的写入之后,最初启动 Compaction 作业,它会一直地产生 Changelog。所以上游能够启动流读作业,来流读这张大宽表,写入上游 Clickhouse 和 ES 当中。除此之外,这张大宽外表向多引擎,能够进行 Ad-hoc 查问,你能够应用 Hive、Spark、Flink 或者 Trino 来实时查问。

为什么要抉择 Flink Table Store 呢?因为 Flink Table Store 使用方便,可能低成本实时打宽。

三、V0.3:FTSV0.3 有什么能力来帮忙上述场景

行将公布的 Flink Table Store 0.3,有哪些性能实现上述的场景?

第一个场景,全增量一体导入。在晚期版本中,从 MySQL 把所有数据 Bulk Load 到一张表中。而后,将定期的增量数据 Load 到数仓当中,进行定期的调度作业。

这个流程链路较简单,保护老本比拟高。因为全量增量点位较难以对齐,所以全增量一起导入,前期不必保护。除此之外,须要存储有较强的写入、更新、删除数据的能力,能力撑得住大数据流量。

Flink Table Store 0.3 大幅加强全量阶段的写入存储,特地是写入时应用的对象存储,0.3 大幅加强吞吐能力,有比拟好的吞吐性。

后续在 0.4 中,也将提供整库同步和 Schema Evolution 同步,将更好的进步入湖的用户体验。

第二个场景音讯队列的流读。作为音讯队列必须要好用,在不申明 Kafka 的状况下,Flink Table Store 表的流读,心愿能做到 30 秒到 1 分钟的提早,跟音讯队列的程序统一。并且 Flink Table Store 也反对多种啊读取模式。比方全增量一起的流读,每次读都能看到所有的数据。

除此之外,你能够通过 from-snapshot,从指定 snapshot-id 开始读增量。你也能够通过 from-timestamp,从指定工夫开始读增量。你还能够指定 Latest,从最新数据,读增量。Flink Table Store 的音讯队列跟 Kafka 齐全对齐。

第三个场景,变更日志流读。

举个例子,如上图所示,当你申明主键之后:

  1. 插入一条数据,主键为 1,column_1 为 1.0.
  2. 再次插入了一条数据,主键仍为 1,column_1 为 2.0.
  3. 此时,对流作业进行流读,SUM 的后果应该是 3.0 还是 2.0?

简略的计算,SUM 的后果就是 3.0,因为呈现过两条数据,所以加起来就是 3.0。然而,这两条数据是雷同的主键,它在更新时应该产生撤回,正确答案应该是 2.0。

Flink Table Store 提供多种 Changelog Producer 模式:

  1. 比方 None,存储不产生 Changelog,交给 Flink SQL 产生。Flink SQL 流读的上游会产生一个相干节点,让上游流作业应用 Changelog Normalize 节点。这个节点的 Cost 比拟大。
  2. 比方 Input,当 input 来自数据库 CDC 的输出,如果能够无条件信赖 input,你能够抉择 Input,来自数据库的 CDC 数据能够保障流读到正确的 Changelog。
  3. 在 Flink Table Store 0.3 中,提供了 Full-Compaction,随着 Full-Compaction 产生完全正确的 Changelog,对流作业的正确性,各种模式的反对十分有用,然而你须要均衡 Full-Compaction 的老本和多久进行一次 Full-Compaction 的时延。

第四个场景,流连贯。存储对流式数仓到底起什么作用?咱们次要规定了三个作用,即音讯队列、长期数据可查、生态好。在 Flink Table Store 0.3,继续加强了生态。以后,流面对的挑战仍有很多,最大的挑战是 Join。典型的 Join 有四种模式能够反对。

第一个模式,双流 Join。假如拿到两个 CDC 的流,依照 Flink SQL 写法,Join 的后果就能够往下写了。此时,Join 要解决两条流,在 Streaming Join 中须要物化,在 State 中保留两个流物化的所有数据。假如 MySQL 中分库分表有 1000 万条,Streaming 中就要保留 1000 万条,而且如果有多个 Join,数据将会被反复的保留,造成大量的老本。

双流 Join 的益处是,Join 的语义十分正确,有保障,任何更新都能正确处理。但它毛病是,老本和性能有比拟大的挑战,其老本十分高。

第二个模式,Lookup Join。假如定义一张叫表叫支流,支流过去须要 Join 补字段。此时,能够把维表当做镜像表,在维表数据来的时候,一直 Lookup 维表数据。Lookup Join 的益处是性能十分好,主表不会乱序,但无奈解决维表的更新问题。

第三个模式,Partial Update。它能够帮忙 Streaming 来做 Join 能力。Partial Up date 的实质是存储自身,具备通过组件来更新局部列的能力。如果两张表都有雷同主键,它们能够别离进行 Partial Update。它的益处是性能十分好,给存储很多空间来优化性能。性能较好,老本较低。但它的毛病是须要有同主键。

第四个模式,Indexed Partial Update。它能够应用 Flink 补齐主键,只须要拿到该主键件和主表主键间的映射关系即可。其次,因为维表的数据量比主表数据量要小很多,所以老本可控。通过应用 Flink 补齐主键之后,以较小 State 解决多流 Join 的问题。

综上所述,咱们心愿提供尽可能多的 Join 模式,让大家依据本人的业务来抉择须要的模式。

四、总结:回顾和我的项目信息

  1. 第一局部,咱们剖析目前 Streaming Data Warehouse 的问题。它的次要挑战是架构,咱们在逐渐解决。
  2. 第二局部,咱们形容 Flink Table Store V0.3 外围解决的场景。
  3. 第三局部,咱们将了讲 Flink Table Store V0.3 哪些性能能帮忙上述案例。
  4. 第四局部,Flink Table Store 会继续加强 Streaming Data Warehouse,来解决更多问题。

如果有需要和问题,请分割咱们!

Flink Table Store 作为 Apache Flink 的子项目,它有本人的用户文档。用户能够通过相干链接,征询相干问题。与此同时,举荐大家入钉钉群,与咱们间接沟通。

点击查看直播回放和演讲 PPT


更多内容


流动举荐

阿里云基于 Apache Flink 构建的企业级产品 - 实时计算 Flink 版现开启流动:
99 元试用 实时计算 Flink 版(包年包月、10CU)即有机会取得 Flink 独家定制卫衣;另包 3 个月及以上还有 85 折优惠!
理解流动详情:https://www.aliyun.com/product/bigdata/sc

正文完
 0