Flink Materialized Table 是什么?一条 SQL 怎么同时管实时和离线?
面试怎么回答
以前同一个指标实时一套 Flink、离线一套 Spark,两份代码两份数据,口径常对不上,新鲜度要求一变就得重写。Flink 1.20 引入的 Materialized Table 让你只写一条查询加一个 FRESHNESS,新鲜度要求高时 Flink 自动起一个持续运行的流作业,要求低时生成周期调度的批作业去刷新,用户不用关心底层是流还是批;还可以 SUSPEND、RESUME、按分区 REFRESH 来补数。它依赖 SQL Gateway 加工作流调度器,存储主要用 Paimon,因为它同时支持流写、批量覆盖和 Changelog。目前还比较新,多层依赖和与现有调度平台的集成还要自己设计,流模式下状态和资源也照常要管理。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
Flink 1.20 引入了 Materialized Table(物化表,FLIP-435),目标是让用户只写一条查询、声明想要的数据新鲜度,由 Flink 自己决定用流作业还是批作业去维护结果。面试官问这题,想看你对流批一体的落地方式有没有了解。
以前的痛点
同一个指标,实时和离线通常是两套:
- 实时链路写一个 Flink 流作业,离线链路写一个 Spark / Hive 批作业;
- 两份代码、两套调度、两份数据,口径还经常对不上;
- 业务对新鲜度的要求变了(比如从 T+1 变成 10 分钟),就要整条链路重写。
Materialized Table 怎么用
核心是 FRESHNESS(新鲜度):
CREATE MATERIALIZED TABLE dws_order_stat
PARTITIONED BY (ds)
FRESHNESS = INTERVAL '3' MINUTE
AS SELECT ds, shop_id, COUNT(*) AS order_cnt, SUM(amount) AS gmv
FROM dwd_order GROUP BY ds, shop_id;
- 新鲜度要求高(低于阈值,默认 30 分钟)时,Flink 启动一个持续运行的流作业(Continuous 模式);
- 新鲜度要求低时,Flink 生成一个周期调度的批作业(Full 模式),按新鲜度定期刷新;
- 用户只关心「查什么」和「多新」,不关心底层是流还是批。
常用的运维操作
ALTER MATERIALIZED TABLE ... SUSPEND / RESUME:暂停和恢复刷新;ALTER MATERIALIZED TABLE ... REFRESH PARTITION (ds='2026-10-01'):手动重刷某个分区,用来补数和修数;- 修改新鲜度后,底层作业的类型可以随之变化。
依赖条件
- 需要 SQL Gateway 作为入口,并配合工作流调度器来调度 Full 模式的批作业;
- 需要一个支持物化表的 Catalog 和存储,目前主要是 Paimon,因为它同时支持流式写入、批量覆盖写和 Changelog 读取;
- 流和批要用同一套 SQL 语义,部分只在流里支持的写法(比如某些窗口语法)要注意兼容性。
局限
- 功能比较新,各版本还在持续完善,复杂的多层依赖、跨物化表的级联刷新等能力不如成熟的调度平台;
- 和公司已有的调度系统(DolphinScheduler、Airflow 等)怎么集成,需要额外设计;
- 流模式下状态、资源的管理仍然要按普通流作业来做。