对象存储+WAL:面向智能体时代的Lakebase Postgres
DataHot 速览
文章介绍 Lakebase Postgres 在分离存储架构下的计算侧缓存改进。数据存放在 S3 等对象存储时,缓存分为分布式存储层和 Postgres 计算层,前者物化页面以支持高写入吞吐和读取,后者用 DRAM 服务高频访问页面。标准 Postgres 的 shared buffers 与 OS page cache 存在双重缓冲:例如 4GB RAM 中 1GB 分配给 shared buffers 时,为缓存 1GB 数据可能占用 2GB 内存。文章还说明已向客户交付的改进,并披露近期计划。
为什么值得关注:数据平台与数据库从业者可了解 Lakebase Postgres 在分离存储下的缓存架构、双重缓冲问题及优化方向,涉及性能与成本等关键权衡。
本文目录 13 节
译文
AI 逐段翻译Lakebase Postgres 的解耦存储模型提供了一个功能丰富、灵活且低成本的平台。当数据后端存储在 S3 等对象存储中时,高效的数据缓存对于提供高吞吐量和低延迟至关重要。
这种缓存发生在两层:在分布式存储中,Postgres 页面被物化以实现高写入吞吐量和读取服务;以及在 Postgres 计算本身之上,从 DRAM 提供频繁访问的页面以实现超快速访问。
我们一直在努力改进计算侧的缓存,在这篇博客中,我们将阐述我们的近期计划,并深入探讨已经交付给客户的内容。
首先,介绍一些我们走到这一步的背景。
标准 Postgres 缓存
数据库对 DRAM(内存)的需求是出了名的。它们主要将此内存用作数据缓存,并期望对缓存中行的访问以纳秒为单位衡量——比最快的 NVMe 驱动器还要快几个数量级。
Postgres 将数据按行组织在页面中,正在被访问的页面必须加载到称为“共享缓冲区”的内存区域中。由于 Postgres 传统上使用操作系统的文件系统来存储页面,OS 内核也会使用其灵活的页面缓存来在 Postgres 共享缓冲区和磁盘之间提供缓存。
这种共享缓冲区 + 页面缓存的方案运行得还算不错,但存在一些缺点和一些挑战。
缺点
- 双重缓冲会减少你可以在计算上有效缓存的数据量。考虑一台具有 4 GB RAM 的计算,其中 1 GB 用于共享缓冲区。当你从磁盘读取页面以填充这 1 GB 共享缓冲区时,读取会经过 OS 页面缓存,而 OS 页面缓存也保存着这些数据。现在你消耗了 2 GB 的 RAM 来缓存 1 GB 的数据。
- OS 页面缓存对共享缓冲区或 Postgres 内部机制一无所知,因此它无法就替换哪些页面做出明智的决定。
技术挑战
- 在Lakebase Postgres 这样的解耦存储系统中,从存储读取的数据不会经过 OS 文件系统或页面缓存。
- 共享缓冲区是一个静态参数,这意味着它在启动 Postgres 之前就已设置,并且在不重启数据库的情况下无法更改。对于像 Lakebase 这样的无服务器自动扩缩容系统来说,这是一个重大的挑战。
- Postgres 为每个活动连接使用一个单独的操作系统进程,因此共享缓冲区越大——即你给 Postgres 的内存越多——OS 就必须为每一个连接做更多的内存管理,这反过来又会消耗内存。
Lakebase 缓存路径

既然我们已经提供了一些背景,现在让我们谈谈我们如何在 Databricks 解决这些问题。
我们期望的最终状态是通过 Postgres 动态共享缓冲区来最高效地利用你计算上的 DRAM,这些缓冲区会随你的工作负载自动扩缩容,并使用最多 75% 的可用内存。
我们最终需要调整我们的计算平台以利用自动扩缩容共享缓冲区,但我们也希望在有可用改进时向客户交付合理的增量改进。每次增量交付都使我们能够自信地交付路线图中的一个或多个部分,同时为客户带来真正的好处。因此,即使自动扩缩容计算是目标,我们也从固定计算开始,如下一节所述。
以下是我们实现的内容。
更大的共享缓冲区

如果你还记得上面的技术挑战,像 Lakebase 这样的解耦系统不会通过标准 OS 文件系统及其页面缓存来路由其读取。还要记住,Postgres 共享缓冲区是静态的,无法自动扩缩容。
为了解决这个问题,我们创建了一个称为本地文件缓存(LFC)的层。LFC 充当替代品,创建了一个与共享缓冲区协同工作的自动扩缩容缓存,并尽可能多地将数据缓存到计算上。这是一个巧妙而务实的解决方案,使 Lakebase Postgres 得以推出自动扩缩容功能,并且自推出以来一直在所有计算上使用。
尽管向用户暴露为单个高速计算缓存,但底层架构支持最多两个层级:
- 共享缓冲区:Postgres 的内存中共享缓冲区,代表最低延迟的访问路径。
- 本地文件缓存:驻留在计算节点本地 NVMe 上的扩展二级缓存,提供比内存更高的容量,但访问页面需要磁盘 I/O。
共享缓冲区被保守地调优,以便在以最小配置 CU 运行时不会消耗过多内存,共享缓冲区的最大配置大小始终不超过 1 GB,而 LFC 消耗总计算缓存容量的其余部分(最多为 DRAM 的 75%)。任何在两个层级都未命中的请求都会从计算节点路由到分布式存储层。
在较大的工作集上,将共享缓冲区限制为 1 GB 迫使大多数缓存命中都要经过较慢的 LFC 层级。LFC 一直很好地为我们服务,但我们的意图是在朝着完全动态共享缓冲区迈进的过程中淘汰其当前形式。
注意:固定计算先行我们首批更大共享缓冲区的交付针对固定大小的计算,因为共享缓冲区还不是动态的。在这些计算上,我们现在禁用 LFC 并将共享缓冲区设置为 DRAM 的 75%。这已在 CU >= 80 的固定大小计算上上线。消除约 1 GB 的缓冲区上限可将热页面保留在最快的存储层,而不是级联到本地文件存储。要查看你的计算是否启用了大共享缓冲区,请运行 show shared_buffers 在 Postgres 连接中。Databricks 中一个 80 CU 的 Lakebase 端点 应该看到值为 20971520。 |
将热数据保留在共享缓冲区而非操作系统页缓存中,也解决了前面描述的那些缺点。不存在双重缓冲,因此 1 GB 的缓存数据消耗 1 GB 内存,而不是 2 GB。而且由于缓存位于 Postgres 内部而非内核中,驱逐决策可以基于对数据库状态的了解来做出——这使我们能够采用比操作系统所能提供的更智能的替换策略。
在固定规格的计算实例上将共享缓冲区设置为 DRAM 的 75% 并不像改一下配置那么简单。这是因为第三个技术挑战——每个后端一个进程的架构。
下一节将介绍我们的解决方案。
用大页解决内存和地址转换开销
Postgres 采用基于进程的结构,每个后端将共享缓冲区映射到自己的地址空间,需要自己的页表项——即内核维护的、硬件用来遍历以将虚拟地址转换为物理内存的结构。默认情况下,Linux 以 4 KB 页为单位进行这种映射。
一些简单的数字:每 1 GB 共享缓冲区对应每个进程 262,144 个页表项。在 32 GB 共享缓冲区和 512 个后端的情况下,这大约是 43 亿个条目,或者说要用约 32 GB 的页表来映射 32 GB 的缓存。
这个工作集也远远超出了转译后备缓冲器(TLB)的容量,TLB 是 CPU 内存管理单元中的缓存,用于加速虚拟地址到物理地址的转换。即便命中共享缓冲区,也会因 TLB 未命中和页表遍历而付出代价。
为缓解这一问题,Postgres 社区建议在使用大型共享缓冲区时采用一种名为大页(每个 2 MB)的操作系统机制。切换到大页可将页表大小减少 512 倍,并显著降低 TLB 未命中率。
在我们的基准测试中,为 Postgres 配置大页后,尾部读延迟最多降低了约 40%,CPU 使用率最多降低了约 30%。
虚拟化环境中的大页支持
Lakebase Postgres 在裸机主机上的轻量级客户虚拟机内运行。内存地址转换涉及两个虚拟化层。要利用大页,需要在整条技术栈上一致地实现:从主机级预留,到为虚拟机内存提供支撑的虚拟机管理程序,再到客户机内核。任何一层出问题都会削弱最终的性能收益。
我们最近在我们的虚拟机基础设施中引入了专用的大页支撑。我们选择使用显式的 2 MB HugeTLB 页,而不是依赖尽力而为的透明大页。现在,为大型固定规格计算实例分配的虚拟机会以预先确定的大页数量初始化,足以满足 Postgres 启动所需。为优化系统资源,计算实例启动时会自动释放超出 Postgres 所需的任何多余大页。
提示:要查看你的计算实例是否启用了大型显式大页,请在 Postgres 连接中运行 show huge_pages。一个 80 CU 的 Lakebase 端点应该看到值为 "on" |
生产环境结果
推广在几周前开始,按区域逐个进行。下面的示例是在启用新配置的重启之后,在大型生产端点上测量得到的。
示例 1:吞吐量约 2 倍,从存储读取次数减少 5 倍
在一个大型端点上,该变更于 8 月 11 日 UTC 时间约 06:10 生效。每秒访问的 Postgres 块数翻了一番,我们在此将其用作吞吐量的代理指标。客户报告称,与前一天、前一周和前一月相比,p50 和 p99 延迟更低。

该端点配置了较大的本地文件缓存。有了更大的共享缓冲区,存储 GetPage/s 从每秒约 8K 下降到约 1.5K。

示例 2:吞吐量 1.3 倍
在另一个大型端点上,该变更于 8 月 14 日 UTC 时间约 01:30 生效。吞吐量上升了约 43%。

计算实例缓存命中率几乎达到 100%,请求几乎完全由共享缓冲区处理。

示例 3:CPU 使用率降低 5 倍,吞吐量提高 2 倍
在此工作负载上,8 月 15 日推广后,CPU 使用从 20 核降至 4 核。计算实例缓存命中率升至接近 100%,实测吞吐量翻了一番。


第 2 部分:自动扩缩容
我们目前正在努力将更大的共享缓冲区带给自动扩缩容的 Postgres 计算实例。自动扩缩容引入了额外的复杂性:我们必须在扩容时动态扩展共享缓冲区,在缩容时收缩它们——同时还要分配精确所需数量的大页。
为了超越固定规格的计算实例,我们开发了一套协议,用于自动扩缩容提供给客户机的大页。大页与动态共享缓冲区同步扩缩,确保即使在高并发和大内存规模下也能维持高效的地址转换。我们的下一篇文章(第 2 部分)将深入探讨这一动态共享缓冲区实现的技术细节,包括开源 Postgres 的当前状态,以及我们选择进一步推进该功能并向上游贡献的领域。
试一试
所有这些性能改进都源于 Lakebase Postgres 架构。存储层充当权威的记录系统,计算节点是无状态的,其内存充当缓存层。
部署 Lakebase Postgres,让性能接受检验。从这里开始。
Lakebase Postgres 可用作独立数据库,你也可以将它与其 Databricks 数据 + AI 平台的其他部分集成:Unity Catalog 治理、湖仓分析、笔记本和 AI 工作流。
补充来源
1 个信源 · 2 篇报道这篇内容对你有用吗?
反馈只用于改善内容筛选,不等同于收藏