从一到无穷大 #52:Lakehouse 不适用时序?打破范式 —— Catalog 架构选型复盘

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。

文章目录

  • 引言
  • [Lakehouse Catalog 的设计初衷与特性](#Lakehouse Catalog 的设计初衷与特性)
  • [Lakehouse Catalog 模式的局限](#Lakehouse Catalog 模式的局限)
  • [自研 Catalog 服务的考量与优势](#自研 Catalog 服务的考量与优势)
  • 结束语

引言

随着数据湖和数据仓库的融合演进,"Lakehouse"架构应运而生,将数据以开放格式直接存储在云对象存储上,同时提供数据仓库级的管理功能。近年来流行的开源表格式如 Delta Lake、Apache Hudi、Apache Iceberg 等,正是这一趋势的产物。它们通过在数据湖上增添元数据管理、Schema evolution、Auxiliary data、Caching、Efficient streaming I/O、数据重组等机制,实现类似数据仓库的 ACID 事务和高性能查询,被广泛用于构建 Lakehouse 平台。

然而,在设计我们自研的云原生时序数据库时,我们面临一个关键决策:是否应采用上述 Lakehouse 表格式及其 Catalog机制,亦或是针对时序场景的特殊需求,开发自有的 Catalog 服务。本文将探讨这一选型过程中的权衡。首先,我们回顾 Lakehouse 表格式的元数据设计初衷与功能特性;接着分析它们在时序数据库场景下可能遇到的局限;最后阐述我们为何选择自研 Catalog 服务,以及这种"自成一体"的方案如何更好地满足云时序数据库的需求。

Lakehouse Catalog 的设计初衷与特性

Lakehouse 表格式(例如 Delta Lake、Hudi、Iceberg)的出现,旨在弥合数据湖的灵活低成本存储与数据仓库的可靠管理功能之间的鸿沟。这些系统通过元数据日志或表格,将对象存储上的文件组织成具备事务一致性的"表",提供诸多传统数据库才有的高级功能。以 Delta Lake 论文为例,可以看到 Lakehouse 类方案普遍支持如下特性:

  1. ACID事务与数据更新:支持对表执行 UPSERT、DELETE、MERGE 等更新操作,并保证事务的原子性和隔离性,从而实现在数据湖上进行可靠的行级别更新和删除。例如 Delta Lake 通过多版本并发控制和乐观锁,实现对云对象存储文件的高效更新,确保这些操作满足 ACID 特性。
  2. Time Travel:支持查询历史快照以及回滚错误数据更新,即提供数据"时间点"查询能力。这使用户能够方便地访问任意过去版本的数据,以应对数据管道出错导致的不良更新或审计需求。
  3. 流式读写:提供流式数据写入和读取优化。例如允许流式作业以小文件低延迟地持续写入数据,然后通过事务方式将其合并为大文件,以提高后续批量查询性能。同时支持对新增数据的快速拉取(日志的存储格式是一系列具有按字典顺序递增ID的.json对象,:消费者只需从它已见过的最后一个日志记录ID开始执行对象存储LIST操作,就能发现新的日志记录),使表既可视作批处理存储,又可作为消息流实时消费。
  4. 缓存机制:利用对象存储上表数据和日志文件不可变的特点,支持工作节点将其缓存到本地 SSD。例如在 Databricks 云服务中,Delta 表可以透明利用本地 SSD 缓存来加速读取。
  5. 数据布局优化:内置数据文件布局重组能力。例如自动调整文件大小、根据指定列对数据重新聚簇(如 Z-Order,Hilbert curves),以提升查询的扫描效率。这些优化任务在后台异步完成,不影响前台查询。
  6. Schema evolution:支持表模式的演化而无需重写已有数据文件。当表架构发生变化时,新旧 Parquet 文件仍能兼容读取,保证 schema 改变的兼容性。
  7. 审计日志:基于事务日志保留所有操作记录,实现审计和数据追溯功能。

上述特性大大提升了在云对象存储上管理表的数据可用性和易用性,被誉为实现"湖仓一体"架构的关键。许多组织因而能够直接在低成本对象存储上完成从批处理、流处理到机器学习的数据分析全流程。

然而,这些强大的功能并非在所有场景下都同等重要。对于我们关注的时序数据库领域,一些 Lakehouse 特性可能并非刚需,甚至会带来额外开销。例如:

  1. Time Travel:在时序数据场景中通常不需要复杂的历史版本查询。时序数据往往更关注最新数据的写入和查询,数据一旦过保留期就被清理,因此无需像湖仓那样维护长时间的多版本快照。
  2. 流式读写:时序数据天然以时间为顺序写入,本身就是一种近实时流式吞吐。对于流处理工作负载,Delta Lake受到底层云对象存储延迟的限制,使用对象存储操作很难实现毫秒级的流处理延迟。时序要求高性能,高并发写入和实时读取,我们有自己的SSD引擎层承载高性能写入和实时查询。
  3. 缓存机制:缓存是云时序数据库的性能基石,我们更倾向在计算引擎层面引入缓存。例如我们采用的计算引擎 Velox 支持文件缓存(AsyncCache),常用数据文件本身大多存放于高速 SSD,本地缓存命中率高;其次我们基于用户负载,使用机器学习,统计等方法主动决策缓存的TTL,淘汰规则和预取,Lakehouse 特有的缓存方案收益有限。
  4. 数据布局优化:时序库通常按照时间分区存储数据,我们已经通过内部的 Compaction 组件定期合并小文件、优化存储布局来提升查询性能,功能上相当于 Delta Lake 提供的优化器。
  5. Schema evolution:时序数据库通常是schema-less的设计,即标签和字段可以动态出现,对于查询层我们有自适应的 Schema 合并逻辑。因此不需要表格式层面显式的 schema 演进支持。
  6. 审计日志:在监控,物联网,车联网等时序场景下,数据一旦写入很少修改,而安全审计通常由上层应用完成,时序数据库对持久化所有操作日志的需求不高。

总的来说,Lakehouse 表格式提供的一系列功能在大数据离线分析场景极为有用,但在云时序数据库这一垂直领域,其重要性需要重新审视。我们更关心的是高并发低延迟写入、按时间范围快速查询、缓存定制化、索引定制化、Compaction、物化视图、降采样等核心需求。

Lakehouse Catalog 模式的局限

尽管像 Delta Lake、Iceberg 等开源表格式为对象存储之上的数据管理提供了便利,但它们的元数据架构也有一些内在限制,尤其在我们目标的时序数据库场景下需要权衡,接下来,我们具体分析采用 Lakehouse Catalog 方案在时序场景下可能遇到的局限。:

  1. 元数据一致性依赖云存储弱保证,引入复杂协调机制 。 基于对象存储的表格式不得不面对底层存储一致性弱的挑战,我们自然使用同部门产品,也就是腾讯云COS,COS并不支持atomic "put if absent" or rename operation[10],非多版本写入是覆盖语义,多版本写入则两份均存在的语义。为实现事务原子性,Delta Lake 在底层存储不支持原子条件写是借助 DynamoDB,Hudi/Iceberg 则依赖外部锁服务(如 Hive Metastore、Zookeeper)来协调并发提交。这些方案在工程上加重了部署和维护负担。例如 Iceberg 常用的 Hive Metastore 锁并非严格强一致,锁超时还可能导致脏写发生。换言之,当前情况下使用开源格式往往仍需要引入额外的协调服务才能确保元数据正确性,而且我们需要再系统里除了引入一个catalog外还要引入一个协调服务,对于项目管理来讲不确定性又多了很多,引入Velox我们已经做了很多的相关修改了,在VeloxCon China 2025我将做一个技术演讲,讨论下我们在Velox上做的适配和优化,而这部分复杂性在自研catalog方案中是可以避免的。
  2. 仅支持单表级别的事务,一致性无法跨表保证: 开放的表格式通常将事务日志限定在表级范围,实现单表的 ACID 保证。三大开源方案均宣称为单一表提供了读写的 ACID 事务,但不支持跨表的原子事务。也就是说,如果一个操作需要同时更新多张表,分别写入各表的事务无法实现原子性提交。这对于需要跨measurement联合更新的场景是不利的。在我们的时序数据库中,虽然多数写入只涉及单一时间序列,但仍希望在元数据层面保留扩展为跨表事务的可能,以确保多个相关表的数据一致性。
  3. 查询规划需读取并合并大量元数据文件,带来开销。 Lakehouse 采用checkpoint+log/manifest文件记录表的变更,这意味着查询引擎在读取表时,需要先解析最新快照对应的所有元数据。例如 Delta Lake 将每次数据变更记录为 JSON 日志,并周期性压缩 checkpoint;Iceberg 将表元数据拆成多级 Manifest 清单。对于大表,查询一个最新视图往往需要读取多个文件并将增量合并才能获取当前有效的数据文件列表。这增加了查询规划的延迟和复杂性。Delta Lake 和 Hudi 通常需要通过一个分布式作业扫描元数据表或日志来获取文件列表,从而在大表上缩短规划时间,但对于小表则引入了不必要的额外延迟。对Iceberg的查询由单个节点进行规划,该节点利用manifest层次结构的上层作为索引,以最大限度地减少必须对下层进行的读取次数,但在极大规模下仍可能遭遇瓶颈。相较之下,我们希望无论大小查询,元数据服务能快速返回当前表的完整文件清单,避免查询前的繁琐合并过程。
  4. 索引支持弱:在Delta Lake和Delta Engine中,我们在用于存储事务日志的同一Parquet文件中,为表中的每个数据文件维护列的最小-最大统计信息,当基础数据按特定列聚类时,这能实现数据跳过优化,在字节的Magnus中引入了文件级别倒排索引和向量索引加速查询,引入了哈希索引和Hfile索引保证主键唯一性。这对于时序场景来讲是远远不够的。

简而言之,尽管 Lakehouse 表格式非常强大通用,其设计权衡是面向开放生态和通用分析的,这和我们云原生时序数据库聚焦的场景存在一定距离。我们需要的是能够针对时序数据的特点进行深度优化的元数据方案,而不是一个为了兼容各种引擎和工作负载而增加诸多功能和层次的通用方案。

自研 Catalog 服务的考量与优势

综合以上分析,我们最终选择摒弃现成的 Lakehouse 元数据方案,转而自研轻量级 Catalog 服务,即采用类似"封闭世界"存储引擎的思路:由我们自己的元数据服务集中管理所有表的信息。这一设计与 Snowflake 等云数据仓库的架构类似,由一个强一致性的服务持有表对象列表的唯一视图(source of truth) 。对象存储在这种模式下被当作Dumb Storage,不需要理解表结构,由元数据服务高效地处理对象的存储、查询和更新。

我们深知这种封闭世界元数据架构在通用场景下被诟病的几点,但也认识到在我们的时序数据库场景下,它的劣势可以被很好地规避,反而能够带来显著优势:

  1. 元数据访问开销低,可控性强:封闭模式下一般担心每次表操作都需联系元数据服务,增加额外跳转。然而在我们的设计中,计算引擎与元数据服务部署在同一云环境,紧耦合优化。例如查询规划时,我们的引擎可直接通过内部RPC高效获取表文件列表,相比通过对象存储扫描目录,解析,合并外部日志,大大降低延迟。此外,由于无需经由第三方连接器,即没有像 Snowflake 连接 Spark 时需要走外部网络流量的问题,我们的查询直接访问底层存储,性能不降反升。
  2. 引擎集成简便,无额外适配成本:我们采用的计算引擎 Velox 是开放源代码的,并已深度融合到数据库内核中。因此,自研元数据服务只需针对 Velox 实现接口即可,而我们的velox是基于时序场景优化的,不需要考虑Lakehouse的多场景(BI,机器学习,Data Science,Report),不需要为每一种可能的引擎开发一套连接器。我们专注于自家的查询引擎优化,避免了为了兼容外部引擎而做妥协。这与Lakehouse追求的"一份数据、多种引擎共享"理念不同。在时序数据库场景下,用户主要通过我们提供的查询接口访问数据,几乎不存在跨各种计算平台自由切换的需求。
  3. 定制功能和扩展性:掌控自己的 Catalog 服务使我们可以针对时序数据特性做定制优化。例如,我们可以在元数据层天然支持跨表的原子批量操作(如果将来有需求),或是实现特定于时序数据的组织方式(如按时间自动分区、过期数据快速清理、基于特定排序规则的文件过滤),这些能力都是通用表格式所不具备或不优雅的。开放格式由于要照顾通用性,很多优化难以针对特定垂直场景。而自研让我们能够快速演进元数据模型,满足新功能的需要,而不受制于外部社区的开发进度。
  4. 无厂商锁定顾虑:Lakehouse倡导使用开放格式避免"数据封闭",允许用户用任意工具访问底层数据。但在云时序数据库场景,我们提供的是一体化的存储与查询服务,数据往往只在本系统内部消费,并不存在多个异构系统共享这一份时序数据的情况。如果用户有迁移需求,通常是整体迁移到另一个系统,而非并行接入多种引擎。因此,我们并不担心所谓"供应商锁定"问题。相反,选择开放格式作为底层可能会束缚我们,因为用户会期望直接访问底层文件,反而影响系统演进,其次我们内部有自研格式增加压缩比和查询性能(Parquet在宽列场景性能较差,后续单独阐述这个问题)。鉴于我们的定位不是打造一个通用 Lakehouse 平台,而是提供一个专用的云时序数据库服务,数据开放访问并非首要诉求。

当然,自研 Catalog 服务也需要我们投入工程精力确保其高可用和性能。但从长期看,这部分投入是值得的。

一方面,我们避免了使用通用元数据服务可能遇到的性能瓶颈,在自研方案中针对时序数据量大、文件众多的特点进行了专项优化(例如元数据存储引擎底层使用了高性能KV并结合内存缓存,加速查询包含数百万文件的大表元信息时的响应)。

另一方面,也可以利用X-Stor多模存储的平台能力,天然支持PITR,备份,迁移,分裂,调度,热点识别,监控,事务等公共能力。

换句话说,我们并非简单否定 Lakehouse 思路,而是取其精华、并结合自身场景做减法和增强。

值得注意的是,业界也有类似思路的实现例证。例如 Snowflake 等云数仓通过在服务中自管理元数据,巧妙避开了对象存储一致性问题,提高了管理效率。Delta Lake 的论文也指出,采用独立元数据服务可以利用传统数据库技术实现高效的元数据操作和搜索。

虽然这种方法要求运行一个高可用服务,运维成本更高,但对于我们提供的云服务而言,这是反而是更简单高效的。同时我们通过架构设计,将查询对元数据服务的依赖对用户透明化,不会产生可感知的延迟。

综上,经过对比权衡,我们认为自研 Catalog 服务的方案更适合云原生时序数据库的定位。Lakehouse 开放表格式在数据湖/仓领域大放异彩,但对于专用型的时序数据库,并不一定是最佳选择。

正如字节在其机器学习数据平台中发现Apache Iceberg尚不能完全满足超大规模需求,最终基于Apache Iceberg构建了 Magnus 元数据系统一样,我们也在时序数据库场景下走出了类似的一步。

自行实现 Catalog 虽有挑战,但带来了性能的一致性、功能的针对性,高性能以及演进的自主性,帮助我们更好地服务时序数据的存储与查询需求。

结束语

Lakehouse 表格式通过统一开放存储与仓库级管理功能,极大地拓展了数据基础架构的边界。然而,技术选型没有银弹,需要结合具体业务场景审慎考量。在云原生时序数据库场景下,我们基于对 Lakehouse 元数据机制优劣的分析,选择了自研 Catalog 服务的道路。这一路径使我们能够聚焦于时序数据的特定需求,实现跨表事务、高效元数据访问等能力,并规避许多通用方案的不必要开销和限制。在实践中证明,自研方案很好地支撑了我们大规模时序数据的管理,性能和可靠性均满足预期。

展望未来,我们将持续关注开源 Lakehouse 生态的发展,同时结合时序场景的演进,不断改进我们的元数据服务。在数据基础架构领域,"从一到无穷大"的探索永无止境------唯有充分理解各种技术方案的设计初衷与权衡取舍,才能在具体问题上做出最明智的选择。

参考

  1. Apache Iceberg 演进
  2. 从 Delta 2.0 开始聊聊我们需要怎样的数据湖
  3. Apache Iceberg: An Architectural Look Under the Covers
  4. 【论文分享】从Lakehouse看Databricks对下一代数据湖架构的理解
  5. Delta Lake & Lakehouse
  6. Magnus: A Holistic Approach to Data Management for Large-Scale Machine Learning Workloads
  7. Delta Lake: High-Performance ACID Table Storage over Cloud Object Stores
  8. Analyzing and Comparing Lakehouse Storage Systems
  9. Lakehouse: A New Generation of Open Platforms that Unify Data Warehousing and Advanced Analytics
  10. Integeration of Tencent COS in Hadoop
相关推荐
拉不动的猪3 小时前
如何处理管理系统中(Vue PC + uni-app 移动端):业务逻辑复用基本方案
前端·javascript·架构
杨筱毅3 小时前
【底层机制】Linux内核4.10版本的完整存储栈架构讲解--用户空间到物理设备完整IO路径
linux·架构·1024程序员节·底层机制
brzhang5 小时前
A Definition of AGI:用人的智力模型去量 AI,这事靠谱吗?
前端·后端·架构
周杰伦_Jay8 小时前
【 RocketMQ 全解析】分布式消息队列的架构、消息转发与快速实践、事务消息
分布式·算法·架构·rocketmq·1024程序员节
腾讯云开发者8 小时前
腾讯元宝搜索实践:大模型时代,AI 如何让搜索焕发新生
架构
Somehow0078 小时前
从Binlog到消息队列:构建可靠的本地数据同步管道(macOS本地部署Canal & RocketMQ并打通全流程)
后端·架构
百锦再8 小时前
国产数据库替代MongoDB的技术实践:金仓数据库赋能浙江省人民医院信息化建设新展望
java·开发语言·数据库·mongodb·架构·eclipse·maven
小二李10 小时前
nestjs 架构篇:控制器、服务、数据访问
架构
消失的旧时光-194311 小时前
Flutter 响应式 + Clean Architecture / MVU 模式 实战指南
android·flutter·架构