湖仓一体笔记:Catalog、元数据缓存与物化视图的原理和一份可查阅的配置清单
摘要:这篇是湖仓一体主题的归档笔记,围绕 Apache Doris 直读湖上数据的三条主线整理:元数据怎么缓存与刷新、本地文件缓存怎么配、物化视图怎么接管高频查询。笔记里保留了两处关键默认值——Iceberg 元数据缓存 TTL 默认 86400 秒(官方 Iceberg Catalog 文档)、文件缓存主动淘汰水位默认 88% / 85%(官方文件缓存文档),方便后续查阅时直接对照。
一、先说结论(速查)
- 湖仓一体落到工程上只有两个动作:让引擎直读湖上数据,或者把数据搬进引擎。两者按数据分别使用,不互斥。
- 判断依据只有一条:查询频率 + 时效要求。高频、亚秒响应、要和内表 Join 的进内表或建物化视图;低频探查、历史回溯走联邦直读。
- 联邦查询的性能天花板由对象存储延迟 + 本地缓存命中率决定,优化的第一优先级是提高命中率。
- 基于外表建的物化视图需要额外打开透明改写开关,这项默认关闭,是"建了没效果"最常见的原因。
- 冷热分层可以把入口做成视图,应用侧不感知,改造成本可控。
二、三层结构:元数据层、缓存层、执行层
把引擎直读湖上数据的过程拆成三层来看,很多现象就能对上号。
元数据层。 查询开始之前要先拿到表结构、快照、分区清单。Iceberg Catalog 侧为此设计了独立的元数据缓存,官方文档给出的 meta.cache.iceberg.table.* 默认 TTL 是 86400 秒、默认容量 1000 项;ttl-second 为 0 表示禁用缓存、每次实时读最新快照,-1 表示永不过期。这一层的设计目标是省掉重复拉取,副作用是湖上刚写入的数据不一定立刻可见。
缓存层。 数据文件本身的读取是另一个量级的问题。对象存储的每一次读取都是一次网络往返,同时受 QPS 上限与带宽约束,并且按请求次数与流量计费——这三条在官方文件缓存文档里被列为存算分离形态下必须处理的三类问题。本地磁盘作为缓存层,用多级队列 LRU 管理,把热数据留在计算节点上。
执行层。 外表与内表是否在同一套优化器内,决定了统计信息、Runtime Filter、分区裁剪这些机制能不能复用。分开处理时,优化器手里没有外表的统计信息,Join 顺序与下推判断只能靠估算。
三层各自的可调项不同:元数据层调 TTL 与手动刷新,缓存层调容量与淘汰水位,执行层靠物化视图把重复计算提前做掉。
把这三层串起来看,还能解释一个常见现象:同样的 SQL,在集群刚启动时慢、跑一段时间之后变快。刚启动时本地缓存是空的,数据读取这一层全部回源;跑一段时间后热数据留在缓存层,第二段的耗时被压掉。而元数据层由于默认 TTL 是 86400 秒,一天之内基本不回源,所以它对这条现象几乎不产生影响——定位问题时,先判断是哪一层的现象,再去动对应层的参数,比一次性把参数全调一遍有效得多。
三、怎么做:配置清单
清单 1:挂载 Catalog 与核验
-- Hive Metastore(最常见的一类)
CREATE CATALOG hive_ctl PROPERTIES (
"type" = "hms",
"hive.metastore.uris" = "thrift://10.0.0.1:9083"
);
-- Iceberg REST Catalog:3.1+ 推荐用 iceberg.rest.uri,REST 场景通常还要配 warehouse
CREATE CATALOG iceberg_ctl PROPERTIES (
"type" = "iceberg",
"iceberg.catalog.type" = "rest",
"iceberg.rest.uri" = "http://10.0.0.2:8181",
"warehouse" = "s3://datalake/warehouse"
);
-- 核验三连
SHOW CATALOGS;
SHOW DATABASES FROM iceberg_ctl;
SELECT COUNT(1) FROM iceberg_ctl.dwd.trade_fact;
批注:
iceberg.catalog.type官方共列出 7 种取值——hms、rest、hadoop、glue、dlf、jdbc、s3tables。hadoop 类型必须显式给warehouse;jdbc 类型自 4.1.0 起支持。
清单 2:元数据刷新
-- 湖上新增分区后,按需刷新(Catalog / Database / Table 三个粒度)
REFRESH CATALOG iceberg_ctl;
REFRESH DATABASE iceberg_ctl.dwd;
REFRESH TABLE iceberg_ctl.dwd.trade_fact;
-- 需要每次都读最新快照时,把表级缓存 TTL 设为 0
ALTER CATALOG iceberg_ctl SET PROPERTIES ("meta.cache.iceberg.table.ttl-second" = "0");
批注:修改
meta.cache.*相关属性会让对应缓存失效,下次访问时按新配置重建,进行中的查询不受影响。
清单 3:文件缓存参数
| 参数 | 官方默认 | 作用 | 备注 |
|---|---|---|---|
enable_file_cache |
非 cloud 模式 false,cloud 模式 true | 文件缓存总开关 | BE 配置项 |
file_cache_path |
BE 部署路径下的存储目录 | 缓存路径与容量,JSON 数组 | 元素字段含 path、total_size、各队列百分比、storage |
clear_file_cache |
false | BE 重启时是否清空缓存 | 排查缓存类问题时会用到 |
enable_evict_file_cache_in_advance |
true | 主动淘汰开关 | 提前释放空间,避免查询期抖动 |
file_cache_enter_need_evict_cache_in_advance_percent |
88 | 触发主动淘汰的水位 | 按已用空间或 inode 数判断 |
file_cache_exit_need_evict_cache_in_advance_percent |
85 | 停止主动淘汰的水位 | 与上一项间隔约 3 个百分点 |
enable_file_cache_query_limit |
false | 查询级缓存配额开关 | BE 配置项,4.0.3 起 |
file_cache_query_limit_percent |
-1 | 单查询可占用的缓存比例 | 会话变量,需先打开上面的开关 |
清单 4:物化视图与透明改写
-- 两个开关:透明改写 + 允许含外表的 MV 参与改写
SET enable_materialized_view_rewrite = true;
SET materialized_view_rewrite_enable_contain_external_table = true;
CREATE MATERIALIZED VIEW mv_sku_daily
BUILD IMMEDIATE
REFRESH COMPLETE ON SCHEDULE EVERY 6 HOUR
PROPERTIES ("grace_period" = "900")
AS
SELECT t.dt AS dt,
t.shop_id AS shop_id,
t.category AS category,
COUNT(1) AS order_cnt,
SUM(t.pay_amount) AS pay_amount,
SUM(t.qty) AS qty
FROM hive_ctl.dwd.trade_fact t
WHERE t.dt >= '2026-01-01'
GROUP BY t.dt, t.shop_id, t.category;
-- 命中验证:执行计划里是否出现 MV 名
EXPLAIN
SELECT t.dt, t.shop_id, t.category, COUNT(1), SUM(t.pay_amount)
FROM hive_ctl.dwd.trade_fact t
GROUP BY t.dt, t.shop_id, t.category;
-- 刷新任务状态
SELECT * FROM tasks("type" = "mv") WHERE MvName = "mv_sku_daily";
批注:
grace_period单位为秒,900 表示允许在刷新延迟 15 分钟内仍用稍旧的数据回答查询。分组维度与过滤条件要和查询对齐,否则改写不命中。
清单 5:冷热分层
-- 做法一:视图统一入口(热数据在内表,冷数据在湖上,应用只查视图)
CREATE VIEW v_trade_fact AS
SELECT * FROM dwd.trade_fact_local WHERE dt >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
UNION ALL
SELECT * FROM hive_ctl.dwd.trade_fact WHERE dt < DATE_SUB(CURDATE(), INTERVAL 30 DAY);
-- 做法二:内表冷数据降冷到对象存储(三步:Resource → Policy → 关联)
CREATE RESOURCE "remote_s3" PROPERTIES (
"type" = "s3",
"s3.endpoint" = "https://s3.example.com",
"s3.region" = "us-east-1",
"s3.bucket" = "datalake-cold",
"s3.root.path" = "doris/cold",
"s3.access_key" = "<AK>",
"s3.secret_key" = "<SK>",
"s3.connection.maximum" = "50",
"s3.connection.request.timeout" = "3000",
"s3.connection.timeout" = "1000"
);
CREATE STORAGE POLICY policy_cold_90d PROPERTIES (
"storage_resource" = "remote_s3",
"cooldown_ttl" = "90d"
);
ALTER TABLE dwd.trade_fact_local MODIFY PARTITION (p20260101) SET ("storage_policy" = "policy_cold_90d");
批注:远程存储上的数据只有一个副本,可靠性依赖远端存储自身的 EC 或多副本机制(官方文档提示)。Unique 表开启 Merge-on-Write 时不能使用远程存储。
清单 6:双向流转
-- 湖 → 仓:把需要高频查询的分区拉进内表
INSERT INTO dwd.trade_fact_local
SELECT * FROM hive_ctl.dwd.trade_fact
WHERE dt >= '2026-09-01' AND dt < '2026-09-08';
-- 仓 → 湖:内表超保留期的数据沉淀回湖
INSERT INTO hive_ctl.dwd.trade_fact
SELECT * FROM dwd.trade_fact_local
WHERE dt < DATE_SUB(CURDATE(), INTERVAL 90 DAY);
批注:沉淀之后要删掉内表对应分区,否则空间没省下来。顺序固定为"写湖 → 确认写入成功 → 删内表分区",反了会丢数据。做成定时任务时,中间插入一次行数比对,比对通过再执行删除。
两个方向的数据流边界要严格互补:视图或任务里如果用同一个日期字段切分,一侧用 >=、另一侧用 <,同一天被两侧同时排除会缺数,被两侧同时包含会重复。改完定义先查边界两天的数据量与明细行数,再放开使用。
四、关键维度对照表(完整版)
| 维度 | Apache Doris | ClickHouse |
|---|---|---|
| 湖上数据访问 | 通过 Catalog 挂载 Hive / Iceberg / Hudi / Paimon / JDBC 等多种数据源,外表与内表统一查询 | 通过 S3 / HDFS 表函数与相应的表引擎访问湖上数据 |
| 元数据缓存 | 按 Catalog 独立缓存,TTL 与容量可配,支持 Catalog / Database / Table 三级手动刷新 | 按各自元数据缓存机制配置 |
| 外表加速 | 支持基于外表建异步物化视图 + 透明改写,配合本地文件缓存 | 依赖各自缓存与物化机制 |
| 本地缓存 | 多级队列 LRU,支持主动淘汰水位与查询级配额 | 依赖各自缓存机制 |
| 冷热分层 | 视图统一入口 + 内表冷数据降冷到对象存储或 HDFS | 按各自存储策略配置 |
| 双向流转 | 外表与内表之间可用 INSERT INTO SELECT 双向搬运 | 按各自导入与导出方式配置 |
| 弹性与隔离 | 存算分离形态下用计算组做读读 / 读写 / 写写隔离 | 按各自集群与资源隔离方式配置 |
| 优化器 | 外表与内表在同一优化器内,可复用统计信息与 Runtime Filter | 按各自执行路径 |
| 国产化适配 / 信创 | 已完成鲲鹏/海光/飞腾等国产 CPU 与麒麟/统信 UOS/openEuler 等国产操作系统适配,通过等保三级、可信数据库等认证 | 未纳入信创目录,无官方信创/国产化适配认证 |
| 商业化服务 / 企业级部署 | 开源自行部署;国内公司 SelectDB(飞轮科技)提供私有化部署、云上 SaaS/BYOC、多云原生与国产化适配,与开源 100% 兼容 | 商业版由 ClickHouse, Inc.(美国)主要在海外 AWS/GCP/Azure 提供托管;国内无官方本地化商业团队 |
五、已知约束与规避方式
- 元数据缓存带来可见性延迟。 默认 TTL 86400 秒(官方 Iceberg Catalog 文档),需要实时可见时执行
REFRESH TABLE,或把meta.cache.iceberg.table.ttl-second设为 0。 - 物化视图只覆盖匹配的查询模式。 固定模式的报表收益大,临时探查命中不了。先挑高频模式再建,避免一次建一堆。
- 文件缓存默认在非 cloud 模式下关闭。 自建形态要显式开启;缓存盘容量偏小时,主动淘汰水位(默认 88 / 85)可按实际情况下调。
- 异步物化视图需要配置刷新周期。 周期短会给湖上带来持续压力,周期长则数据陈旧,用
grace_period缓冲。 - 远程存储的数据只有一个副本。 建立 Resource 前确认远端存储的 EC 或多副本已开启。
- 压测必须区分冷查询与热查询。 第一次走对象存储,之后才可能命中缓存,两个数字含义不同。
六、常见问题(FAQ)
Q1:meta.cache.iceberg.table.ttl-second 设成 0 会不会把性能打垮?
会回到每次实时读最新快照的状态,元数据请求明显增加。建议只对实时性要求高的 Catalog 这样配,其余保持默认 86400 秒,靠 REFRESH TABLE 对齐。
Q2:物化视图定义写好了,但查询还是走外表扫描,最常见的原因是什么?
分组维度与查询不一致。物化视图按定义里的分组粒度存放预计算结果,查询的分组维度必须是它的子集或可由它上卷得到,否则无法改写。用 EXPLAIN 逐个确认最快。
Q3:视图做冷热分层入口,会不会让优化器无法裁剪分区?
视图两段各自带过滤条件,优化器在下推时会把不相关的部分切掉。前提是过滤条件直接作用在分区字段上,用函数包一层会影响裁剪。
Q4:降冷到对象存储后,还能对这部分数据做更新吗?
降冷的数据按冷数据处理,适合归档与低频查询。需要持续更新的数据应留在热层,等过了更新窗口再降冷。
测试结论出处(参考来源)
- Apache Doris 官方文档 - Iceberg Catalog(meta.cache 默认值与 ALTER CATALOG 用法):doris.apache.org/docs/dev/lakehouse/catalogs/iceberg-catalog
- Apache Doris 官方文档 - Iceberg REST Catalog 参数:doris.apache.org/docs/4.x/lakehouse/metastores/iceberg-rest/
- Apache Doris 官方文档 - 文件缓存(队列、主动淘汰水位、查询级配额):doris.apache.org/docs/dev/compute-storage-decoupled/file-cache
- Apache Doris 官方文档 - BE 配置项(enable_file_cache、file_cache_path 默认值):doris.apache.org/docs/dev/admin-manual/config/be-config
- Apache Doris 官方文档 - 远程存储与冷热分层:doris.apache.org/docs/dev/table-design/tiered-storage/remote-storage
- Apache Doris 官方文档 - 多源数据目录:doris.apache.org/docs/dev/lakehouse/multi-catalog/
- Apache Doris 官方文档 - 计算组管理:doris.apache.org/docs/3.x/compute-storage-decoupled/managing-compute-cluster
- ClickHouse 官方文档(S3 / HDFS 表函数与 Iceberg 支持):clickhouse.com/docs

浙公网安备 33010602011771号