将Postgres数据以Parquet格式存储在S3上:LTAP架构解析

Hacker News Top 产品

摘要

Databricks推出Lakebase LTAP架构,将Postgres数据以Parquet格式存储在S3上,无需CDC或镜像即可在单份数据上实现事务与分析。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/04 09:38

# 从单体到Lakebase再到LTAP:从存储层重新思考数据库 来源:https://www.databricks.com/blog/lakebase-ltap-rethinking-database-storage 16年前我在加州大学伯克利分校开始攻读博士学位时,我的导师告诉我:“OLTP数据库已经是个解决完毕的问题了。它们能工作。专注于分析吧。”那时我们正处于能够收集更多结构化与非结构化数据的早期阶段,并应用机器学习(我们现在称之为“AI”)。所以我听从了建议,与联合创始人一起参与了后来成为Apache Spark的研究项目,之后我们创立了Databricks。 在构建Databricks的过程中,我们开始使用各种现存的数据库,并意识到OLTP数据库远非解决完毕:它们笨重、难以扩展,而且极其脆弱。某个时刻我们感到足够沮丧,于是问自己:如果今天来设计一个OLTP数据库,它会是什么样子?这个问题引出了[Lakebase](https://www.databricks.com/blog/what-is-a-lakebase),我们的无服务器Postgres数据库。 本文将深入探讨Lakebase的OLTP架构。我们从传统单体数据库的存储层开始,分析痛点来源;然后看Lakebase如何将同样的组件重新排列为独立的外部化服务。最后,我们转向[LTAP](https://www.databricks.com/company/newsroom/press-releases/databricks-launches-ltap-first-lake-transactionalanalytical),在该架构下,事务和分析可以在同一份数据上实时运行,无需CDC或“镜像”带来的延迟和额外成本。 ## **数据库作为单体** 当今世界上运行的绝大多数数据库都是单体架构。这包括MySQL、Postgres、经典Oracle。Lakebase基于Postgres(巧合的是,它也[诞生于伯克利](https://www.postgresql.org/docs/current/history.html)),因此我们主要用Postgres作为示例,但大多数数据库的工作方式类似:你配置一台机器来运行数据库引擎和存储。在这些数据库系统中,磁盘上最重要的两样东西是:*预写日志(WAL)*和*数据文件*。 当你提交一个事务时,数据库不会立即去重写数据文件。那样会很慢,因为你触及的行分散在文件中,需要随机I/O。相反,数据库首先将变更描述追加到WAL中,这是一个磁盘上的顺序日志。一旦该日志条目被持久化写入,事务就视为已提交。之后,数据库才会异步地回过头来更新实际的数据文件以反映变更。 **一个简单的理解方式:WAL的存在是为了让*****写入*****快速(且安全),而数据文件的存在是为了让*****读取*****快速。**日志让你能够通过一次顺序追加提交事务,而不是分散的随机I/O。数据文件让你可以直接读取当前状态来回答查询,而无需从头重放整个数据库历史。(如果你想了解这个设计的所有复杂细节,请阅读长达69页的[ARIES论文](https://web.stanford.edu/class/cs345d-01/rl/aries.pdf)。警告:这是计算机科学中最复杂的论文之一。) 由于这种设计已成为几乎所有数据库的基础,单体架构也带来了许多挑战: **配置错误导致数据丢失。**一次提交的持久性取决于其背后的磁盘刷写。如果数据库、操作系统或存储层的配置导致WAL写入在真正刷写到持久化介质之前就向客户端确认,那么一次提交可能在断电或内核恐慌中消失。这些设置很微妙,容易出错,而且失败往往是静默的。操作系统甚至可能[在刷写问题上对你撒谎](https://www.postgresql.org/message-id/flat/CAMsr%2BYHh%2B5Oq4xziwwoEfhoTZgr07vdGG%2Bhu%3D1adXx59aTeaoQ%40mail.gmail.com)! **节点丢失导致数据丢失。**即使刷写配置正确,WAL和数据文件也存在于一台机器上。如果该机器的磁盘损坏,上面的数据也会丢失。注意,网络附加存储或RAID-1/RAID-10等冗余技术可以提高持久性,但并未从根本上解决这个问题。如果存储挂载点损坏,你的数据访问也会丧失。 **扩展读取需要物理克隆。**当一台服务器无法承载你的流量时,标准答案是添加一个只读副本。但只读副本是整个数据库的完整物理副本,它从主节点流式传输WAL并重放。配置一个只读副本意味着复制整个数据集,然后追赶日志。对于大型数据库,这可不是一个快速操作,甚至可能导致数据库宕机。 **高可用性也需要物理克隆。**要应对主节点丢失,至少需要运行一个额外的备用节点,它本身是通过WAL保持同步的完整物理副本。你需支付至少两倍的基础设施成本,需要很长时间才能使备用节点上线,并且必须设置同步复制以避免主节点宕机时丢失数据。(实际上,许多[建议](https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION-HA)使用3个或更多节点。) **分析任务与事务流量争抢资源。**一个繁重的分析查询在与你对延迟敏感的事务工作负载相同的硬件资源上运行。一个大型报表查询或一次GDPR清理可能会降低你的主要OLTP查询性能。你可以在单独的副本上运行分析查询,但最终你仍需为副本付费,而且由于OLTP存储的行导向特性(分析需要列导向存储才能获得高性能),仍然无法获得最佳性能。 这些问题的几乎每一个都可以追溯到单体架构的同一个根本原因:WAL和数据文件存储在单台机器内部。持久性依赖于那台机器的磁盘。扩展和可用性需要物理克隆那台机器。工作负载相互干扰,因为它们共享同一台机器。 ## **Lakebase架构** 如果今天要重新设计一个OLTP数据库,你会从现代云的组件开始:廉价且高度持久的云对象存储,搭配弹性计算。这正是Neon团队所走的道路,也是Lakebase的基础。 核心举措是让Postgres计算实例变为*无状态*。我们通过将本地磁盘上的WAL和数据文件外部化为专用、独立可伸缩的服务来实现这一点。计算层变成了一个无状态的Postgres引擎,可以自由地启动、停止和复制,因为它不再拥有数据。 让我们看看这两个存储服务如何协同工作,在不牺牲性能的情况下解决上述挑战。 ## **扩展写入:WAL变成SafeKeeper** 在单体中,一次写入通过刷写到本地磁盘变得持久。在Lakebase中,WAL被外部化为一个名为*SafeKeeper*的分布式存储服务。持久性不再依赖磁盘刷写,而是通过基于Paxos的网络复制将日志记录在SafeKeeper节点仲裁间复制来实现提交的持久性。不再有会因为故障而丢失数据的磁盘,也不再有配置错误的刷写悄悄破坏你的持久性保证。 此时自然会问:将提交从本地磁盘的WAL移动到SafeKeeper上的WAL是否会因为额外的网络跳转而增加写入延迟?答案是不会。对于任何关心持久性和可用性的严肃Postgres部署,你都需要设置同步复制,这本身就需要额外的网络跳转,因此将WAL外部化到SafeKeeper并不会带来额外开销。事实上,由于Postgres的内部工作方式,SafeKeeper和PageServer的组合可以带来[5倍更高的写入吞吐量和2倍更低的读取延迟](https://www.databricks.com/blog/how-lakebase-architecture-delivers-5x-faster-postgres-writes)。 ## **扩展读取:数据文件变成PageServer** 数据文件移动到另一个名为*PageServer*的分布式存储服务。WAL从SafeKeeper流式传输到PageServer,PageServer异步地将这些变更应用到其数据版本中,将页面物化到低成本云对象存储(湖)中。你可以将PageServer视为底层对象存储的写透缓存。 这与单体中的WAL-然后-数据文件关系类似,只是两部分现在位于独立、可伸缩的服务中,通过网络连接而不是放在同一块磁盘上。当从PageServer请求一个页面时,如果PageServer还没有最新版本(请记住,变更首先写入SafeKeeper,然后才到达PageServer),PageServer会应用来自SafeKeeper的日志来重建最新状态。 类似的问题:将数据文件从本地磁盘移到PageServer是否会因为额外的网络跳转而增加读取延迟?实际上答案也是不会。该系统旨在通过激进的多层缓存来隔离并最小化延迟影响。为了获取一个页面,Postgres首先查看其缓冲池(位于节点的本地内存中)。页面不存在时,它会查看本地磁盘缓存。只有在缓存未命中时才需要去PageServer。由于计算节点可以配置与单体设置相同的本地内存和磁盘容量,你的本地缓存命中率保持不变。对于绝大多数操作,读取延迟与单体无法区分,但你可以获得解耦、几乎无限的存储带来的好处。 ## **这解锁了什么** 一旦WAL位于SafeKeeper,数据文件位于PageServer,许多在单体中困难或不可能的功能就变成了架构的自然结果。以下功能已作为Lakebase产品的一部分在Databricks和Neon上广泛可用: **仍然是Postgres。**这是真正的Postgres,因此线路协议、SQL、驱动程序和扩展都能原样工作。 **无限存储。**数据存在于云对象存储中,而不是在预配的本地磁盘上。你不再需要为容量上限而对服务器进行尺寸规划。实际上,存储是无限的。 **无服务器、弹性计算。**由于计算是无状态的,它可以在负载下瞬间扩展,并在空闲时缩至零。你不需要为一台闲置等待流量的大型机器付费。 **持久写入和零数据丢失。**一旦提交通过Paxos在SafeKeeper节点间复制,它就是持久的,而不是当单个本地磁盘声称已刷写时。任何单个节点的丢失都不会丢失已提交的数据。 **更简单的高可用性。**在单体中,HA意味着维护第二个完整的物理副本,支付双倍费用,并且仍然存在切换时数据丢失的风险。在这里,持久状态已经存在于独立于任何单个计算实例的复制存储层中。故障转移不再意味着提升一个单独的数据库物理副本,并希望日志的最后一段成功传输过来。 **即时分支、克隆和恢复。**这是我最喜欢的。对于代码,创建分支是亚秒级的、完全隔离的整个代码库副本,我们每天会做几十次,无需思考。对于单体数据库,克隆意味着物理复制整个数据集,这既慢又昂贵,且对生产系统有风险。当数据存在于外部化、版本化的存储层中时,分支或克隆是一个元数据操作,而不是物理复制。你可以在几秒钟内分支一个大型生产数据库,在分支上运行实验或风险迁移,然后丢弃它。时间点恢复也是如此工作。数据库终于可以像你的代码一样快速移动。 将计算与存储分离本身并不是新鲜事。前一篇文章[讨论了做到这一点的第二代云数据库](https://www.databricks.com/blog/what-is-a-lakebase)。然而,Lakebase的关键在于我们将操作数据以开放格式存储在通用对象存储上。这样,我们为其他引擎直接读取数据打开了机会,从而引出了LTAP。 ## **LTAP:一份数据同时用于事务和分析** 到目前为止,所有内容都是关于让单个操作数据库变得更好:更持久、更弹性、运行成本更低、分支更快。但一旦数据存在于外部化的存储层中,更有趣的事情就成为可能。我们可以不再将事务数据库和分析系统视为两个独立的世界。 暂时回到PageServer。它已经从WAL获取变更流,并异步地将页面物化到对象存储中。这个物化步骤——数据落入湖中的那一刻——恰好是解决一个更古老问题的正确位置…… 即使有了Lakebase,对象存储中的数据仍然以Postgres的本地页面格式写入,按行布局。这种格式对事务很好,但对分析很差,因此任何想要读取它的分析引擎要么每次读取时都付出转换成本,要么更常见的是依赖一个通过管道保持同步的单独数据副本。管道可能很脆弱,数据的两个副本可能成为权限分散的治理噩梦。 我们最近宣布了[LTAP](https://www.databricks.com/company/newsroom/press-releases/databricks-launches-ltap-first-lake-transactionalanalytical),即湖区事务/分析处理,它消除了两个数据副本的问题。关键思想是在*存储*层而不是*引擎*层统一两个世界。我们并不试图构建一个在事务和分析两方面都表现优异的引擎。我们为每个任务保留最佳工具:Postgres,具有完整ACID语义用于事务;Lakehouse引擎用于分析。改变的是它们底下的数据。不再是两种格式的两个副本,而是一份持久的副本,采用Delta和Iceberg等开放列式格式,以Parquet存储,双方都可以读取(并配有各种级别的缓存以获得更好性能)。 ## **以列式形式物化** 注意:本节需要比其它部分更多的Postgres内部知识才能理解。 当PageServer将页面物化到对象存储时,它在数据落入湖时会将Postgres数据从行格式转码为Parquet的列式布局。我们保留每个值的精确Postgres表示,直至位级别,因此任何兼容Postgres的引擎都可以重新解释它而不会丢失信息。这与基于CDC的方法不同,CDC将一系列逻辑变更事件传送到外部模式中,并丢弃了Postgres的物理和事务语义;这里我们保留了它们。借助超优化的引擎,PageServer层的空闲CPU在将数据物化到对象存储的过程中执行行到列式的转码,因此不会给处理你事务的Postgres计算增加负担。为了高效服务事务性读取,PageServer仍然在本地缓存中物化传统的基于行的页面,但这严格来说是一个性能缓存。底层持久存储仍然在湖中统一,可供双方访问。 **在列式形式中保留Postgres语义**

相似文章

Databricks 推出 LTAP:统一的 OLAP/OLTP 数据架构

Hacker News Top

Databricks 推出 LTAP(湖事务/分析处理),这是一种新的架构,在数据湖中基于单一数据副本统一 OLAP 和 OLTP,消除 ETL 管道,并由 Lakebase 提供支持。这为 AI 应用时代的操作数据、分析数据和流数据提供了单一受管的基础。

大规模并行 Postgres 备份

Hacker News Top

PlanetScale 描述了它如何通过为每个分片启动 EC2 实例、从对象存储恢复之前的备份并重放 WAL,来对分片 Postgres 数据库执行大规模并行备份,从而实现超过 50 GB/s 的 PB 级备份速度。

Parquet 中定长列表的快速路径

Lobsters Hottest

这篇博客文章介绍了 Apache Parquet 的一项优化,用于高效存储和解码像向量嵌入这样的定长列表,通过绕过固定大小数据页的 Dremel 重构,实现了与扁平列相当的解码性能。