🏢 公司C档 · NaN分

Doris 5.0,把流和湖缝上了

··约1分钟阅读

📋 总体概括

Apache Doris 5.0 原生读取 Fluss 日志表与主键表,并通过 Union Read 把 Paimon 湖上历史与流上增量缝进一次查询,同时解决了实时读取下的 JVM 内存管控问题。本文拆解其技术路径与产业含义:数据不搬家、查询一个入口,正在成为实时分析的新默认。

📄 正文

凌晨两点的大促作战室里,最尴尬的问题从来不是流量,而是对不上账。

实时大屏说 GMV 冲破了某个数,湖里的 T+1 报表却是另一个数。业务方问一句“以哪个为准”,数据团队只能解释:一条是流链路,一条是批链路,口径和时点都不一样。

这个延续了十几年的老问题,正在被一条 SQL 简化。Apache Doris 5.0 直接读取 Apache Fluss(2025 年初进入 Apache 孵化器的流式存储项目,由阿里巴巴捐赠)的日志表和主键表,并通过 Union Read 把 Apache Paimon 里的历史数据与流上的最新数据合并在一次查询里返回。核心判断只有一句话:数据不再为了被查询而搬家,查询入口正在向“一个”收敛。

先把版本脉络摆清楚,方便核实:Doris 对 Paimon 等湖格式的原生读取自 2.1 版本(2024 年 3 月发布)通过 Multi-Catalog 机制提供,3.0 版本补齐了存算分离架构;Fluss 提供日志表与主键表两种表形态,并通过官方 Tiering Service 把日志数据周期性下沉到 Paimon;本次 Doris 5.0 补上的是最后一块——查询引擎对 Fluss 流存储的原生直读与流湖合并。下文涉及的具体能力,均以 Apache Doris、Apache Fluss、Apache Paimon 的官方文档与发行说明为准(文末附链接)。

🎯 对不上账的大促夜

金句先行:不是数据不够快,是数据被搬了太多次。

典型场景是这样的。一家电商平台的数仓团队维护着两条链路:批链路走 Flink 写 Paimon,再由调度任务定期合并产出报表;流链路走 Kafka 加实时计算,供大屏和风控使用。同一个“订单成交”事件,在两条链路里各走一遍,各自清洗、各自聚合。链路重复开发、口径两套维护、存储双份成本、排查问题时两头比对——这组成本在 Lambda 架构的经典论述(Jay Kreps 2014 年那篇《Questioning the Lambda Architecture》)里就被点名,此后历次流批一体的工程实践讨论中反复出现。

Doris 5.0 的变化在于,查询引擎原生具备了读 Fluss 流存储的能力——无论是保留变更日志、适合追加和回放的日志表,还是支持持续更新、自带 KV 快照的主键表,都可以直接作为查询对象。湖上的 Paimon 数据照常可查,流上的新鲜数据也照常可查。

产业逻辑其实很朴素:过去为了让不同引擎“认识”流数据,团队要么把流数据落成批表,要么维护专门的实时服务层。现在查询引擎自己走向了流存储,中间那些为搬运而生的环节,价值就被稀释了。架构收敛的方向,永远是从“多跳”走向“少跳”。

🔍 Union Read:全量在湖,增量在流

金句先行:湖存历史,流存热点,一张表收口。

Union Read 是这次能力的关键机制。它做的事可以用一句话概括:当用户查询一张同时存在 Paimon 历史和 Fluss 增量的逻辑表时,Doris 会同时读取两边的最新状态,把湖上的存量数据和流上的近期变更合并后,作为一个统一结果返回。

这背后是 Fluss 的两种表形态在分工:

维度日志表主键表
写入模式追加写入,保留完整变更日志按主键持续更新,定期生成 KV 快照
典型用途事件明细、审计、重放维表、订单状态、实时特征
读方收益顺序扫描快,适合明细分析免去下游去重与合并
在链路中的角色由 Tiering Service 周期性下沉为 Paimon 湖表湖表尚未覆盖时段的实时“热层”

整条查询路径大致如下:

而对架构师来说,更值得关注的是分工方式的变化。以前数据按“团队和用途”分家:报表归批链路、大屏归流链路。现在数据按“温度和访问模式”分层:历史、冷数据、全量留湖上;高频变更、新写入进流存储;查询引擎在顶层一个入口收口。

从 Fluss 官方文档的 Lakehouse 章节和 Doris 的发行说明看,“流表当湖表热层”的用法正在从大厂的自建方案变成开源组合里的标准姿势。原因无他:过去这套语义要靠自研服务层硬扛,现在查询引擎直接提供了。

⚙️ 真正的坎:内存管控

金句先行:实时架构演示看功能,上线看内存。

Union Read 听起来优雅,工程上却有个绕不开的难题。一次查询要同时面对两类负载:湖上 Paimon 的历史数据量大而可预估,流上 Fluss 的数据却是持续写入、边界不定的。两股数据在一个查询里汇合,内存的分配与回收就成了稳定性胜负手——处理不好,轻则查询超时,重则 OOM 拖垮整个节点。

需要先澄清一个容易误读的细节:Doris 的查询执行主体是 C++ 的后端(BE),但对 Fluss 的读取走的是 Fluss 的 Java 客户端,这条路径上的堆内存必须单独管控。Doris 5.0 在 Union Read 场景下做了两件事,依据官方发布说明与文档:

1. 查询级内存配额。Doris 自 2.x 起就有 MemTracker 与 Workload Group 机制——BE 进程内存上限默认约为物理内存的 80%(mem_limit),Workload Group 可以按租户设定软/硬内存限额,超限查询排队或被终止。Union Read 把流侧扫描纳入同一套配额体系,避免“读流”绕开管控成为内存黑洞。

2. 流侧拉取的有界化。流存储的读没有天然终点,Doris 通过限制单批次拉取的数据量、设置扫描超时,把“边界不定的流”切成可预估的批次;配合 2.1 版本起提供的算子落盘(spill to disk)能力,排序、聚合等中间结果超出内存预算时可溢写到磁盘,而不是直接 OOM。

这套机制在 PPT 上只有一行字,在内核团队那里却是长期的工程投入。

从各厂商公开的故障复盘和社区 issue 讨论看,实时分析引擎的线上事故,大头从来不是功能缺失,而是内存与并发——尤其在“一条查询同时扫湖读流”这种混合负载场景。⚠️ 这也是为什么同样的架构图,不同引擎画出来都差不多,真正拉开差距的是 Workload Group 的隔离粒度、spill 的触发阈值这些没人愿意写进宣传稿的细节。

产业判断也随之清晰:实时分析的基础设施竞争,正在从“能不能”进入“稳不稳、贵不贵”的阶段。Union Read 这类能力决定产品能不能入选,内存管控和资源隔离决定产品能不能留下来。

🆚 放进棋盘里看:与其他引擎的实质差异

金句先行:读湖的引擎不少,读流又管得住内存的没几个。

只看功能清单,“联邦查询”并不新鲜,需要把 Doris+Fluss+Paimon 这套组合放进竞品棋盘里比:

方案读 Paimon 湖表读流存储流湖合并语义内存/资源管控
Doris 5.0 + Fluss原生支持(2.1 起 Multi-Catalog)原生直读 Fluss(5.0 起)Union Read,一次查询合并Workload Group + MemTracker + spill
StarRocks 3.x原生支持(3.1 起支持 Paimon)依赖外部管道,无流存储直读需自行落批有资源组(Resource Group)机制
Trino / Presto依赖 Paimon 官方连接器不支持,Kafka 连接器只做消费不做合并查询无统一语义会话级内存上限,管控粒度较粗
ClickHouse需外部 ETL 落本地表Kafka 表引擎消费后落表,非“边写边查”无按用户/查询配额,但湖生态薄弱
传统 Lambda(Flink + Kafka + OLAP)支持支持(经 Flink)双链路各自维护,口径靠人肉对齐依赖 Flink 作业级内存配置

三点实质差异值得强调:

  • 对 Trino/Presto:联邦查询一直能“同时查多个源”,但缺乏流湖合并的语义层——同一张逻辑表的湖部分和流部分,在它眼里是两张独立的表。Union Read 的价值不在“能连上”,而在把合并的正确性(时点对齐、主键去重)下沉到引擎。
  • 对 StarRocks:两者同源(Doris 与 StarRocks 均源自百度 Palatino / 后续分叉),读湖能力基本对齐。当前差别主要在流存储侧:StarRocks 尚无对流式存储的原生直读,实时数据仍需经 Flink 落批或维护 StarRocks 内表。这条线谁先跑通、谁先在内存管控上稳住,将直接影响下一轮选型。
  • 对 ClickHouse:ClickHouse 在单表极致扫描上长期占据 ClickBench 公开榜单前列,但它与湖格式的生态距离较远,“流湖一体”叙事在其架构里基本不存在——这本身就是一种路线分野。

至于性能,公开可查的口径是:Doris 官方技术博客在 TPC-DS 1TB 对比中声称对 Trino/Presto 有数倍优势(倍数以官方口径为准,且属于厂商自测);ClickBench 等第三方榜单可作为点查与扫描场景的横向参考。 Union Read 场景本身尚无独立第三方基准,这正是评估时应主动要求 POC 复现的部分——谁拿官方数字替代自己的 workload 验证,谁就把风险留给了自己。

🏗️ 一张图看懂格局变化

金句先行:流湖一体的竞争,本质是查询引擎话语权的竞争。

把 Doris、Fluss、Paimon 三者的角色放进一张图,会更直观:Fluss 承担流式写入与变更存储,Paimon 承担湖上历史与开放表格式生态,Doris 承担统一查询出口。三者各司其职,语义上拼出一个完整的“流湖仓”闭环。

这条路线的产业含义有两层。

第一层是成本。流批双链路意味着双份开发、双份存储、双份运维,收敛到一个查询入口后,重复建设和口径漂移的成本被直接削减。对于数据团队规模有限的中小公司,这是从“养不起”到“用得起”的区别。

第二层是话语权。当查询引擎可以直接读流存储和湖表,引擎层和数据层的边界被重新划定:表格式和流存储继续开放,查询入口则越来越向少数成熟引擎集中。谁能同时把湖读好、把流读稳、把内存管住,谁就能占据这条链路里议价能力最强的位置。

当然,也要保持一份冷静。⚠️ 流湖一体的落地效果高度依赖工作负载:对于以高并发点查为主、对毫秒级延迟极度敏感的场景,独立实时服务仍有其价值;但对于分析型负载占主导的大多数企业,“一个查询入口 + 分层存储”正在成为更务实的默认解。

📌 小结

从 Lambda 到 Kappa,再到今天的流湖一体,十来年的架构摇摆,最终落点是绕不开的常识:数据只该存一份,口径只该维护一套,用户只该面对一个入口。

Doris 5.0 读 Fluss、Union Read 融合 Paimon、实时负载下的内存管控——这三件事拼在一起,让“一条 SQL 查流又查湖”从口号变成了可上线的工程方案。下一步值得观察的是:StarRocks 等同位引擎是否会跟进对流存储的原生读取,以及流存储(Fluss)与表格式(Paimon)之间的边界会不会被 Tiering Service 进一步抹平。数据不搬家这件事,才刚刚开始兑现它的成本红利。

信息锚点(供核实):

  • Apache Doris 官方文档:Multi-Catalog 与湖格式读取(doris.apache.org/docs,Lakehouse 章节)、Workload Group 与内存管理章节
  • Apache Fluss 官方文档:Table 设计(Log Table / Primary Key Table)、Lakehouse 与 Tiering Service 章节(fluss.apache.org)
  • Apache Paimon 官方文档:各计算引擎连接器支持矩阵(paimon.apache.org)
  • Jay Kreps, Questioning the Lambda Architecture(O'Reilly Radar, 2014)
  • ClickBench 公开榜单(clickbench.com);TPC-DS 对比数据来自厂商官方博客自测口径,未经第三方复现

编辑说明:本次修订①将“业内人士私下流传”“接近引擎社区的人士”等模糊信源替换为可公开核实的文档、论文与榜单锚点,无法核实引语句已删除;②补齐版本脉络(Doris 2.1/3.0/5.0、Fluss 进入 Apache 孵化器时间)、内存管控具体机制(MemTracker、Workload Group、spill、流侧拉取有界化)并澄清了“JVM 内存”表述中的架构细节;③新增与其他引擎的实质对比章节,并明确标注了厂商自测数据与第三方基准的区分。建议发布前由作者确认 Fluss 进入 Apache 孵化器的准确时间及 Doris 5.0 发布说明中的细节表述。

本文由本站 AI 辅助聚合生成,原始来源如下:

🔎 本文基于以下资讯(素材溯源 · 信息来源)

📰 相关阅读推荐(与本文相关的其他资讯)