Flink Materialized Table 是什么?一条 SQL 怎么同时管实时和离线?

第 1267 题 约 3 分钟读完

本文目录
  1. 面试怎么回答
  2. 以前的痛点
  3. Materialized Table 怎么用
  4. 常用的运维操作
  5. 依赖条件
  6. 局限

面试怎么回答

以前同一个指标实时一套 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 等)怎么集成,需要额外设计;
  • 流模式下状态、资源的管理仍然要按普通流作业来做。