禁用 Postgres FPW 实现写入性能 5 倍提升
摘要
本文介绍了 Databricks 的 Lakehouse 架构如何通过禁用全页写入(FPW)并利用无状态计算与分布式存储,使 Postgres 的写入吞吐量提升 5 倍。
暂无内容
查看缓存全文
缓存时间: 2026/05/10 18:44
# Lakebase 架构如何实现 5 倍更快的 Postgres 写入
来源:https://www.databricks.com/blog/how-lakebase-architecture-delivers-5x-faster-postgres-writes
在 Lakebase(https://www.databricks.com/blog/what-is-a-lakebase)中,计算与存储在设计上便是分离的。虽然这种分离最初是为了提供操作灵活性(包括扩展、分支和即时恢复)(https://neon.com/docs/introduction/architecture-overview),但它也开启了巨大的性能前沿。
通过解耦这些层级,我们可以将工作负载从您的 Postgres 计算层卸载到我们的分布式存储层,这在传统的单体 Postgres 部署中在结构上是不可能的。在本文中,我们将探讨如何利用这种架构优势,消除一个困扰 Postgres 长达十年的瓶颈,从而将 Postgres 写入吞吐量提高 5 倍,同时将读取尾部延迟降低 2 倍,WAL(预写式日志)流量减少 94%。
## **传统 Postgres 持久性的隐藏成本**
为了了解我们如何在托管 Postgres 性能上实现 5 倍的提升,我们需要回顾传统 Postgres 如何处理持久性。
在 Postgres 中,每次数据库更改首先保存到顺序日志(即预写式日志,WAL)中,以确保在崩溃时数据不会丢失。为了保持快速崩溃恢复时间,Postgres 定期执行称为“检查点(checkpoint)”的后台清理事件。**与快照不同,检查点仅仅是日志中的一个里程碑标记。** 在检查点期间,Postgres 会将当前内存中所有修改过的数据(以称为“页”的 8KB 块管理)刷新到主磁盘,直到日志中的特定点。如果发生崩溃,Postgres 将从该检查点里程碑开始,并在磁盘上重放最近的 WAL 日志来恢复您的数据。
然而,存在一种风险:如果服务器在将 8KB 页保存到磁盘时恰好崩溃,该页可能只被部分写入,导致损坏的“撕裂页(torn page)”。如果 Postgres 尝试在撕裂页上重放微小的日志更新,数据将被永久破坏。为了解决这个问题,Postgres 必须确保它永远不依赖损坏的磁盘进行恢复。
它通过“全页写入(Full Page Write, FPW)”来实现这一点。在检查点里程碑之后*首次*修改某个页时,Postgres 不仅记录微小的更改,还会将整个 8KB 页复制到 WAL 中。如果发生崩溃且磁盘页撕裂,Postgres 会忽略损坏的磁盘,从 WAL 中获取 pristine(完好无损)的 8KB 备份,并将其作为重放其余日志的完美起点。虽然这保证了绝对的安全性,但代价高昂:在写密集型应用中,记录整个 8KB 页可能会使日志体积膨胀多达 15 倍,往往成为系统最大的性能瓶颈。
## **Lakebase 解决方案:消除撕裂页风险**
在 Lakebase 架构中,您的计算层是无状态的。它不依赖本地数据目录。相反,它将 WAL 流式传输到基于 Paxos 的 safekeeper(安全守护进程)多数派。
由于没有本地磁盘页可供撕裂,FPW 旨在防止的故障模式根本不存在。然而,简单地关闭 FPW 会引发次要问题:读取性能。如果日志中没有那些定期的全页镜像,存储层将不得不重放无限长的小增量链,以重建读取请求所需的页。曾经有界的 O(检查点频率)重放变成了无界链,导致读取延迟和资源消耗的激增。
## **创新:将镜像生成下沉到分布式存储**
我们通过将智能从计算节点转移到存储层解决了这个问题。我们称之为镜像生成下沉(image generation pushdown)。
当 Postgres 计算层向存储请求某个页时,pageserver(Lakebase 分布式存储系统的组件)通过找到该页最新的物化镜像并在其上重放任何 WAL 增量来重建它。计算层过去嵌入在 WAL 中的全页镜像充当了增量链中的定期重置点,自然地使链保持合理有界,从而保持读取速度。有关此机制的更深入探讨,请参阅《深入 Neon 存储引擎》(https://neon.com/blog/get-page-at-lsn)。
禁用全页写入后,这些重置点消失了。如果没有分布式存储系统中的额外智能,频繁更新的页可能会积累长长的增量链,中间没有镜像。结果是,当 pageserver 重放整个链以响应读取请求时,读取延迟和资源消耗会不理想地增加。
为了避免这个问题,我们将镜像生成责任从计算的 WAL 流下沉到存储层,在消除计算层 WAL 开销的同时,保持了存储层有界的读取行为。现在,当一个页在没有中间镜像的情况下积累的增量记录超过配置的阈值时,pageserver 会生成全页镜像。这是一种更优的方法,因为生成新镜像的决定是基于对页的实际更改次数,而不是与无关的 Postgres 检查点过程。
**为什么这对性能有显著提升:**
1. **网络效率:** 计算层仅发送紧凑的增量(即实际更改),在我们的基准测试中导致**流量减少 94%**。
2. **可扩展性:** 工作负载从单个 Postgres 写入者转移到分布式、可独立扩展的存储层。项目分支的镜像生成现在在后台由多个 pageserver 共享。
3. **最优读取:** 镜像生成的时机现在基于对页的实际更改,而不是无关的 Postgres 检查点过程。
## **量化影响:从实验室到生产环境**
我们使用 HammerDB(https://www.hammerdb.com/)TPROC-C(一种源自 TPC-C 的 OLTP 基准测试)对此优化进行了基准测试,并在真实世界的生产工作负载中验证了结果。
### **1. 无服务器计算扩展**
吞吐量以每分钟新订单数(NOPM)衡量。收益随着计算实例规模的增大而显著增加:
**计算规模** | **之前 (NOPM)** | **之后 (NOPM)** | **吞吐量增益**
---|---|---|---
**4 vCPU** | 78,876 | 94,891 | **20%**
**16 vCPU** | 95,832 | 269,189 | **2.8 倍**
**32 vCPU** | 95,686 | 439,300 | **4.5 倍以上**
在 32 vCPU 计算实例上,改进幅度超过了 450%。
当全页镜像在计算层生成时,每笔交易平均产生 58KB 的 WAL。当下沉镜像生成后,这一数字降至 4KB 以下——减少了 94%。吞吐量的提升随之而来:更少的 WAL 意味着写入路径上的争用更少、消耗的网络带宽更少,以及存储层摄取的工作量更少。
通过移除 Postgres 的 FPW 瓶颈,我们允许吞吐量随计算资源线性扩展。这是单体 Postgres 在重写入负载下难以做到的。
### **2. 真实世界生产环境验证**
在一个高知名度的 56 vCPU 项目的生产环境中,启用镜像下沉将稳态 WAL 生成率从 30 MB/s 降低到仅 1 MB/s。
生产客户 WAL 速率:(越低越好)
这一体积的减少与日常峰值期间的交易吞吐量增加直接相关。
这不仅有助于写入。通过优化增量链,每次读取必须应用的 WAL 记录数量显著下降。我们看到 p99 读取延迟降低了 30% 到 50%,p50 延迟降低了约 30%。
生产客户吞吐量:(越高越好)
从区域层面来看,启用后我们观察到由计算层生成的 WAL 总量减少了多达 4 倍。存储引擎的读取 p99 延迟提高了多达 3 倍,并且变得更加稳定。
区域 WAL 摄取速率(越低越好)
区域存储 p99 页检索延迟(越低越好)
### **3. Lakebase 同步表**
对于数据密集型同步表,影响是立竿见影的。一位客户在启用镜像下沉后,摄取吞吐量从每秒 17,000 行跃升至每秒 62,000 行,实现了 3 倍的增长。
## **无缝部署:性能提升且无中断**
自 3 月下旬以来,我们已在整个集群中部署了此项改进。它目前在全球所有的 Lakebase Serverless 和 Neon 数据库中处于活动状态。
该更改通过我们的控制平面和存储系统应用于运行中的计算实例,自动协调过渡。这是利用现有的 Postgres `XLOG_FPW_CHANGE WAL` 记录机制实现的,这意味着我们的客户无需重启或中断服务。
## **托管 Postgres 性能的下一步是什么?**
Lakebase 架构旨在提供灵活性,但其设计初衷是为了性能。下沉全页写入是**系统性努力**(https://neon.com/blog/recent-storage-performance-improvements-at-neon)的一部分,旨在收获存储与计算分离的好处。
就像我们引入**缓存预热**以实现零停机补丁(https://www.databricks.com/blog/zero-downtime-patching-lakebase-part-1-prewarming)一样,我们继续将繁重的工作从您的事务中移出,放入我们可扩展的后台存储堆栈中。Postgres 写入税正式成为过去式。
相似文章
将Postgres数据以Parquet格式存储在S3上:LTAP架构解析
Databricks推出Lakebase LTAP架构,将Postgres数据以Parquet格式存储在S3上,无需CDC或镜像即可在单份数据上实现事务与分析。
Making Postgres 300x faster for analytics: batching, operator fusion, and SIMD
pgrust 0.2 rebuilds the Postgres query engine with batching, operator fusion, and SIMD, achieving 300x faster analytical queries and 30% faster OLTP than Postgres.
如何写入SSD
本文提出了针对数据库系统的异地写入优化,以充分利用SSD性能,在OLTP基准测试中实现了1.65-2.24倍的吞吐量提升和6.2-9.8倍的闪存写入减少。
大规模并行 Postgres 备份
PlanetScale 描述了它如何通过为每个分片启动 EC2 实例、从对象存储恢复之前的备份并重放 WAL,来对分片 Postgres 数据库执行大规模并行备份,从而实现超过 50 GB/s 的 PB 级备份速度。
@_avichawla: Cloudflare如何在不离开Postgres的情况下将查询时间缩短35倍:他们的Postgres表达到数十亿行,而每次时间范围查询开始变慢。
Cloudflare使用TimescaleDB(Tiger Cloud)在数十亿行的Postgres表上将查询性能提升了35倍,并借助Claude Code和Tiger CLI构建了一个实时地震仪表板。