你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:
- 了解大厂经验
- 拥有和大厂相匹配的技术等
希望看什么,评论或者私信告诉我!
在数据处理领域,Apache Flink 一直是流处理和批处理的佼佼者。随着数据量的不断增长和业务需求的日益复杂,如何简化数据管道的开发和管理成为了亟待解决的问题。
Flink 的 Materialized Table 应运而生,它为开发者提供了一种全新的方式来构建和管理数据管道。本文将深入探讨 Flink 中 Materialized Table 的背景、它所解决的问题、当前的进展以及如何使用它。
一、背景
目前的数据仓库处理架构中,既有流批分离的 Lambda 架构,也有基于流批存储统一处理模型的 Lakehouse 架构,但这两种架构都存在一些问题:
-
Flink SQL 提供了流处理和批处理两种执行模式,用户需要根据数据新鲜度的要求来选择合适的模式。在流处理模式下,使用 INSERT INTO 语句;在批处理模式下,则使用 INSERT OVERWRITE 语句。此外,分区表的分区条件也存在异构性,这导致用户需要维护两套代码,增加了开发和维护的复杂性。
-
当与现代流批统一存储结合使用增量计算模型时,如果需要批量刷新某些历史分区,流作业代码逻辑无法直接重用。这需要重新开发具有指定分区条件的批处理作业代码,以避免全表刷新,可能导致数据重复。
-
此外,手动创建和部署作业是必要的。对于流作业,用户需要微调诸如检查点间隔、小批处理等参数,这在优化方面可能成本高昂。对于批处理作业,需要使用如 Airflow 等工作流调度器来创建作业。这些是两个分离的系统,在修改数据新鲜度要求时无法无缝切换。
为了解决上述问题,Flink SQL 引入了基于动态表概念的新型表类型,称为物化表(Materialized Table),以经济高效的方式简化流和批 ETL 管道。这使得用户不再被各种复杂的概念如流处理和批处理以及底层技术细节所困扰,只需专注于业务逻辑和数据新鲜度。
二、Materialized Table 优势
(一)统一流批处理
Materialized Table 基于流批统一存储和增量计算模型,允许用户通过一套代码来应对不同的数据新鲜度要求,无需在流处理和批处理之间进行切换。这不仅降低了开发成本,还提高了数据处理的灵活性。
(二)简化数据管道开发
通过 Materialized Table,用户可以使用统一的声明式 SQL API 来定义数据的批处理和流处理转换。这意味着用户无需关心 Flink 作业和执行模式的细节,只需专注于业务逻辑和数据新鲜度的要求。例如,创建一个 Materialized Table 的语句如下:
sql
CREATE MATERIALIZED TABLE dwd_orders
(
PRIMARY KEY(ds, id) NOT ENFORCED
)
PARTITIONED BY (ds)
FRESHNESS = INTERVAL '3' MINUTE
AS SELECT
o.ds,
o.id,
o.order_number,
o.user_id,
...
FROM
orders as o
LEFT JOIN products FOR SYSTEM_TIME AS OF proctime() AS prod
ON o.product_id = prod.id
LEFT JOIN order_pay AS pay
ON o.id = pay.order_id and o.ds = pay.ds
当执行这条语句时,会根据查询语句推导出表的架构,在 Catalog 中创建一个 Materialized Table,并根据指定的新鲜度自动创建数据处理管道来刷新表。
(三)灵活的数据刷新
Materialized Table 支持多种操作来管理数据刷新,包括暂停、恢复、手动刷新和更新数据等。例如,可以通过 SUSPEND 和 RESUME 语句来暂停和恢复表的数据刷新,也可以通过 REFRESH 语句来手动刷新特定分区的数据。
三、实际例子
假设 MySQL 实例中有三个业务表:orders(订单表)、orders_pay(订单支付表)和 products(产品类别维表),我们将对这三个表进行数据宽化操作。
按照传统的逻辑,它们首先通过 Flink CDC 实时摄入到 Paimon 等湖存储中进行处理,需要手动部署作业等等。
但现在看看用户如何基于物化表来创建数据处理管道,以及如何通过动态表暂停和恢复数据管道。
(一)创建数据管道
orders 和 order_payments 是 ODS 层的两个基础表,按 ds 分区。在这里,我们创建一个 DWD 宽表 dwd_orders。
sql
CREATE MATERIALIZED TABLE dwd_orders
(
PRIMARY KEY(ds, id) NOT ENFORCED
)
PARTITIONED BY (ds)
FRESHNESS = INTERVAL '3' MINUTE
AS SELECT
o.ds,
o.id,
o.order_number,
o.user_id,
...
FROM
orders as o
LEFT JOIN products FOR SYSTEM_TIME AS OF proctime() AS prod
ON o.product_id = prod.id
LEFT JOIN order_pay AS pay
ON o.id = pay.order_id and o.ds = pay.ds
当执行创建物化表语句时,会根据引用的查询语句推导出表的schema,首先在 Catalog 中创建一个Materialized Table,然后根据指定的新鲜度 Freshness 值自动刷新表。由于这里新鲜度设置为 3 分钟,因此会启动一个 Flink 流作业来持续刷新。
(二)暂停与恢复数据管道
sql
-- 1. 暂停表数据刷新
ALTER MATERIALIZED TABLE dwd_orders SUSPEND;
-- 2. 恢复表数据刷新
ALTER MATERIALIZED TABLE dwd_orders RESUME
-- 通过 WITH 子句设置表选项
WITH(
'sink.parallelism' = '10'
);
- 通过 SUSPEND 语句,可以暂停刷新作业。
- 通过 RESUME 语句,可以恢复刷新作业。
(三)手动刷新
sql
-- 刷新历史分区
ALTER MATERIALIZED TABLE dwd_orders REFRESH PARTITION(ds='20231023')
如果需要对分区表的某些历史分区进行回填,只需执行 REFRESH 语句并指定分区条件,这将启动一个 Flink 批处理作业来刷新表。
通常,为了符合 GDPR 等要求,可能需要修改表中的某些数据,这可以通过 Update 语句来完成。
sql
UPDATE dwd_orders SET order_number = 10 WHERE id = 73635185;
(四)修改数据新鲜度
sql
ALTER MATERIALIZED TABLE dwd_orders SET FRESHNESS = INTERVAL '1' DAY
如果需要调整数据新鲜度,只需修改物化表的新鲜度属性。它会首先停止 Flink 流作业,然后自动在工作流调度器中创建一个定时任务。工作流将根据指定的新鲜度触发表刷新。
从上述操作过程可以看出,使用 Materialized Table 可以大大简化数据处理管道的开发。通过使用统一的声明式 SQL API 来统一流和批管道,用户无需关心 Flink 作业和执行模式,只需操作物化表即可。
通过带有声明 SQL 语句和新鲜度的 Materialized Table,来加速 ETL 管道开发,自动管理任务编排,提升数据质量和新鲜度,节省您的时间和精力。
四、目前的进展
Materialized Table 的引入是 Flink 在简化数据管道方面的重要进展。它不仅解决了现有架构中的诸多问题,还为用户提供了更加便捷和高效的开发体验。目前,Materialized Table 的设计和实现已经取得了一定的成果,但仍有一些限制和未来的改进方向。
(一)限制
- 不支持显式指定列
- 不支持在创建 Materialized Table 后修改 Select 语句
- 目前不支持在 Select 语句中引用临时表、视图或函数
(二)未来改进
- 支持临时视图:虽然目前不支持临时视图,但可以通过使用视图或公共表表达式(CTE)来实现类似的效果。未来可能会根据用户需求和技术实现来决定是否支持临时视图。
- 修改 Select 语句:目前的设计不支持修改查询语句,但在湖仓一体的场景中,由于模式演化需要添加字段,这是一个合理的需求。可能的解决方案是使用 Alter Materialized Table xxx ADD query_statement 的语法来提供支持,并在框架级别优化多个写入同一 Materialized Table 的查询语句。
五、怎么用
(一)创建 Materialized Table
使用 CREATE MATERIALIZED TABLE 语句来创建一个物化表,指定其架构、分区键、新鲜度以及定义查询等。例如:
sql
CREATE MATERIALIZED TABLE dwd_orders
(
PRIMARY KEY(ds, id) NOT ENFORCED
)
PARTITIONED BY (ds)
FRESHNESS = INTERVAL '3' MINUTE
AS SELECT
o.ds,
o.id,
o.order_number,
o.user_id,
...
FROM
orders as o
LEFT JOIN products FOR SYSTEM_TIME AS OF proctime() AS prod
ON o.product_id = prod.id
LEFT JOIN order_pay AS pay
ON o.id = pay.order_id and o.ds = pay.ds
(二)暂停与恢复数据刷新
-
暂停表的数据刷新:
sqlALTER MATERIALIZED TABLE dwd_orders SUSPEND;
-
恢复表的数据刷新:
sqlALTER MATERIALIZED TABLE dwd_orders RESUME WITH( 'sink.parallelism' = '10' );
(三)手动刷新
如果需要对分区表的某些历史分区进行回填,可以执行 REFRESH 语句并指定分区条件,这将启动一个 Flink 批处理作业来刷新表。例如:
sql
ALTER MATERIALIZED TABLE dwd_orders REFRESH PARTITION(ds='20231023');
(四)更新数据
为了符合 GDPR 等要求,可能需要修改表中的某些数据,这可以通过 Update 语句来完成。例如:
sql
UPDATE dwd_orders SET order_number = 10 WHERE id = 73635185;
(五)修改数据新鲜度
如果需要调整数据新鲜度,只需修改物化表的新鲜度属性。例如:
sql
ALTER MATERIALIZED TABLE dwd_orders SET FRESHNESS = INTERVAL '1' DAY;
六、总结
Flink 的 Materialized Table 为简化数据管道的开发和管理提供了一种强大的解决方案。它通过统一流批处理、降低开发成本、提高数据处理灵活性等方式,帮助用户更高效地应对复杂的数据处理需求。虽然目前还存在一些限制,但随着技术的不断进步和社区的努力,这些问题有望得到解决。对于需要构建高效、灵活数据管道的开发者来说,Materialized Table 是一个值得深入探索和应用的技术。