Postgres 17 与 18 版本性能对比

18版本新增两种替代方案:worker和io_uring。worker(新默认值)会让Postgres使用专用的后台工作进程处理所有I/O操作。io_uring因性能优势备受期待,它利用Linux的io_uring接口实现所有磁盘读取的异步处理,有望显著提升I/O性能。


Postgres 18 于数周前发布,其带来的改进引发了广泛热议。最值得关注的是,Postgres 18引入了io_method配置选项,使用户能够更精细地控制磁盘I/O处理方式。

将该选项设为sync时,行为与17及更早版本一致,所有I/O均通过同步请求处理。

18版本新增两种替代方案:workerio_uringworker(新默认值)会让Postgres使用专用的后台工作进程处理所有I/O操作。io_uring因性能优势备受期待,它利用Linux的io_uring接口实现所有磁盘读取的异步处理,有望显著提升I/O性能。

我们通过详细基准测试对比了Postgres 17与18的性能表现,验证这些改进是否名副其实。

元素周期表

基准测试配置

测试采用sysbench执行。由于io_uring优化仅适用于读取操作,本文将重点关注oltp_read_only基准测试。该测试涵盖点查询以及由--range_size参数控制的范围扫描和聚合查询。虽然同时测试写入及读写混合性能也很有意义,但专注于只读场景有助于聚焦讨论重点。数据规模设定为TABLES=100SCALE=13000000,生成约300GB数据库(100张表,每张含1300万行)。

测试在四种EC2实例配置上进行:

Instance vCPUs RAM Disk Disk type IOPS Throughput
r7i.2xlarge 8 64 GB 700 GB gp3 3,000 125 MB/s
r7i.2xlarge 8 64 GB 700 GB gp3 10,000 500 MB/s
r7i.2xlarge 8 64 GB 700 GB io2 16,000
i7i.2xlarge 8 64 GB 1,875 GB NVMe 300,000

所有实例均运行于相同(或高度相似)的英特尔CPU平台。我们纳入i7i实例以展示Postgres在高速本地NVMe驱动器上的性能潜力。此配置正是我们PlanetScale Metal所采用的方案,在Postgres 17环境下已取得卓越性能成果。许多其他云服务商仅提供网络附加存储方案,而我们同时支持两种存储模式。

每台服务器在基准测试前均经过10分钟查询负载预热。

针对每种配置,我们分别运行sysbench oltp_read_only基准测试5分钟,配置如下:

  • 单连接且--range_size = 100
  • 10 个连接且 --range_size = 100
  • 50 个连接且 --range_size = 100
  • 单连接且 --range_size = 10,000
  • 10 个连接且 --range_size = 10,000
  • 50 个连接且 --range_size = 10,000

这导致总共产生 24 个独特的 5 分钟基准测试运行。这 24 种配置各运行了四次!一次在 Postgres 17 上,另三次分别在 Postgres 18 的 io_method=workerio_method=io_uringio_method=sync 模式下。由此形成96种基准组合。尽管如此,请尽管说我疯了!

这是极度依赖I/O的工作负载。数据规模(300 GB)远超内存容量(64 GB),因此执行查询时将产生大量磁盘访问。

单连接模式

尽管单连接模式不符合实际生产环境,但它能为不同I/O设置对直线性能的影响提供基准参考。让我们评估在此模式下可达的QPS值。

下图展示了所有单连接运行中--range_size设为默认值100时的平均QPS。这意味着完整读取负载由点查询与100行序列扫描/聚合查询组合构成。

图0:Postgres 17 与 18 版本性能对比

以下几点值得注意:

  1. 在网络附加存储(gp3、io2)环境中,Postgres 18的syncworker模式表现明显优于17版本及18的io_uring模式。我承认这出乎意料!原本预期io_uring至少能与所有选项持平甚至更优。
  2. gp3甚至io2的延迟差异是导致结果差异的关键因素。在配备低延迟本地NVME驱动器的实例上,所有配置方案的性能差距显著缩小。
  3. gp3乃至昂贵的io2驱动器的延迟/IOPS成为性能瓶颈。本地磁盘在所有配置中均表现更优。
  4. 对于短时查询的线性性能,Postgres 18 明显更快。欢迎这些改进!

以下是相同测试但使用 --range_size=10000 的结果。这意味着工作负载包含更大规模的扫描/聚合操作,导致更多顺序I/O操作和更低的QPS:

图1:Postgres 17 与 18 版本性能对比

本地磁盘性能依然明显领先,但其余三种方案的差距已不那么显著。这主要源于:(a) 更高的顺序I/O操作,但更关键的是(b) 更高的CPU负载(聚合10k行数据比聚合100行更耗CPU)。此外,Postgres 17与18版本间的性能差距已大幅缩小。

下方交互式图表对比了所有实例类型在Postgres 17下的结果与Postgres 18中性能最佳的workers实例。点击缩略图可添加或移除图表线条,比较不同组合。数据基于10秒采样率生成。

高并发场景

实际应用中常存在大量并发连接与同时读取操作。让我们观察各服务器在50个连接的高负载环境下执行相同基准测试的表现。

当然,oltp_read_only 无法完全模拟真实的 OLTP 工作负载(尤其未包含写操作),但我们将其作为高读取需求场景的替代方案。下表展示了所有 50 连接 oltp_read_only 测试(--range_size=100)的平均 QPS 值。

图2:Postgres 17 与 18 版本性能对比

在高并行度和增加的I/O需求下,以下几点变得清晰:

  1. 对于所有EBS支持的实例,IOPS和吞吐量都是明显的瓶颈。在这种情况下,不同版本/I/O设置的差异并不显著。
  2. 随着EBS性能提升,QPS呈同步增长趋势,本地NVME实例表现优于所有其他实例。
  3. 在所有EBS实例中,启用syncworker的Postgres 18版本以微弱优势获得最佳性能。

再次进行相同基准测试,但使用--range_size=10000参数。

图3:Postgres 17 与 18 版本性能对比

gp3-10kio2-16k实例性能已逼近本地磁盘水平。但这源于本次基准测试更侧重CPU而非I/O限制,因此本地磁盘的低延迟优势减弱(尽管仍是最佳选择!)。关键在于,我们终于迎来io_uring胜出的场景!在 NVMe 实例上,其性能略优于其他选项。

下面我们再次比较 Postgres 17 和 Postgres 18 中的这些结果,涉及 worker 数量。点击缩略图可在图表中添加或移除行,比较各种组合。

中等并发

相同基准测试在10个并发连接下运行。结果基本一致故不全部展示,但需特别指出--range_size=100条件下的图表:

图4:Postgres 17 与 18 版本性能对比

请仔细观察首组柱状图(对应gp3-3k)。io_uring设置的性能明显逊于其他配置。但当连接数为50时,该配置在同等条件下的表现仅略逊于其他方案。这表明io_uring在高I/O并发场景下表现优异,而在低并发场景中优势不明显。

成本

比较基础设施配置时,成本始终是关键考量因素。以下是AWS中各服务器配置的按需成本:

  • r7i 搭配 gp3 3k IOPS 及 125 Mbps:$442.32/月
  • r7i 搭配 gp3 10k IOPS 及 500 Mbps:$492.32/月
  • r7i 搭配 io2 16k IOPS:$1,513.82/月
  • i7i 搭配本地 NVMe 磁盘(无 EBS):551.15 美元/月

请注意,前三种配置仅提供 700 GB 存储空间,而 i7i 配备 1.8 TB 卷!采用本地 NVMe 磁盘的服务器无疑是性价比之选。

为何io_uring未能胜出?

鉴于我对Postgres 18新增io_uring功能的期待,本以为它能在更多场景中胜出。实际情况为何如此?

首先,这是非常特定的工作负载类型。它仅限读取操作,且同时包含点查询、范围扫描和范围聚合操作。io_uring在其他工作负载场景中必然能展现优势。此外,通过调整postgresql.conf参数,我们或许能看到io_uring的性能提升。

在撰写本文时,我偶然发现了Tomas Vondra的精彩博文,其中探讨了新的io_method选项、调优方法以及各选项的优缺点。他针对workers为何能超越io_uring给出了若干精辟见解,强烈建议您阅读原文。简而言之:

  • 索引扫描(目前)尚未启用AIO。
  • 尽管io_uring将I/O操作移至后台执行,但校验和计算/内存复制仍可能成为瓶颈。
  • 从单进程视角看,workers能实现更高效的I/O并行处理。

因此确实存在io_uring未必更优的合理场景!期待看到更多涵盖不同工作负载类型的配置基准测试。测试使用的多数配置可在附录中查阅。

结论

尽管范围有限,这次对比 Postgres 版本与 I/O 设置性能的实验仍颇具趣味。我的核心发现包括:

  • Postgres 18 带来了显著的 I/O 性能提升和配置灵活性。维护团队做得很好!
  • 本地磁盘表现明显优于其他方案。当具备低延迟I/O和海量IOPS时,其他因素影响较小。这正是PlanetScale Metal能实现业界顶尖数据库性能的原因。
  • 新默认值io_method=worker是明智选择。它兼具io_uring的诸多“异步”优势,却无需依赖特定内核接口,并可通过设置io_workers=X进行精细调优。
  • 不存在万能的最佳I/O配置方案。
  • 尽管有所改善,新的workers I/O配置对网络附加存储场景的助益仍不及预期。

您还希望看到哪些基准测试?欢迎联系我们告知需求。

附录:配置文件

以下是本次基准测试中使用的关键定制化 Postgres 配置选项:

shared_buffers = 16GB          # 25% of RAM
effective_cache_size = 48GB    # 75% of RAM
work_mem = 64MB
maintenance_work_mem = 2GB

wal_level = replica
max_wal_size = 16GB
min_wal_size = 2GB
wal_buffers = 16MB
checkpoint_completion_target = 0.9

random_page_cost = 1.1
effective_io_concurrency = 200
default_statistics_target = 100

max_worker_processes = 8
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
max_parallel_maintenance_workers = 4

bgwriter_delay = 200ms
bgwriter_lru_maxpages = 100
bgwriter_lru_multiplier = 2.0

autovacuum = on
autovacuum_max_workers = 4
autovacuum_naptime = 10s
autovacuum_vacuum_scale_factor = 0.05
autovacuum_analyze_scale_factor = 0.025

logging_collector = on
...more log configs...

shared_preload_libraries = 'pg_stat_statements'
track_activity_query_size = 2048
track_io_timing = on

jit = on

# io_workers left at default = 3

本文文字及图片出自 Benchmarking Postgres 17 vs 18

共有 64 条讨论

  1. 据我所知,此基准测试中没有任何内容会在18版实际使用AIO。截至18版,仅序列扫描、位图扫描、vacuum及少数实用命令支持AIO读取。但当前执行的查询通常应规划为索引范围扫描。我们希望在19版中实现索引扫描的AIO支持,但该功能也可能推迟至20版,这并非易事。

    另需注意数据校验和的默认设置已变更,由此产生部分开销。

    1. 若基准测试未使用AIO,为何博客文章中PG 17与18的性能存在差异(sync、worker和io_uring测试)?

      是否因为云端远程存储始终引入波动性,而基准测试恰好捕捉到了这种波动?

      参考信息:anarazel昨日在pgconf.eu大会上发表了关于AIO的演讲。他提到远程云存储必然引入波动性,导致基准测试结果难以解读。其解决方案是在本地NVMe上引入合成延迟进行测试。

    2. 那么io_uring AIO模式的性能不足就更令人费解了。

      1. 确实如此。我尝试复现但未成功。

        我怀疑这可能只是在性能特征略有差异的不同虚拟机上执行的结果。根据帖子中的描述,我无法判断同一测试的所有运行是否都在同一台虚拟机上执行。

  2. 误差条去哪了?我不明白为什么大家跑这么多测试却不提供标准差数据,也不说明差异是否具有统计学意义。

  3. 我从中获得的核心教训是:

    若注重性能,请勿使用网络存储。

    若使用本地 NVMe 硬盘,Postgres 17 或 18 版本差异微乎其微。性能基本持平,且远超网络存储。

    1. 但存在临时性和非冗余性问题。

      在任何 VPS 上使用本地硬盘是否都存在持久性隐患?

      1. 是的,短暂性才是最大问题。企业级SSD相当可靠,通常配备PLP(电源中断保护),即使突然断电,驱动器已接受并确认fsync()的队列写入操作仍会完成。假设您会部署某种冗余方案,可能是RAID或zRAID(此处假设纯本地存储,非Ceph等分布式系统或同步复制)。

        但在云环境中,若实例背后的物理服务器故障,甚至有人误发关机命令,新实例启动时您将无法恢复原有磁盘。因此原本可通过本地冗余解决的问题突然变得不可行,你必须选择:要么采用同步或半同步复制(PlanetScale Metal采用后者),承受分布式存储带来的延迟损失;要么选择异步复制并接受一定数据丢失风险——后者通常难以接受。

        1. 认同这些权衡。我们根据Postgres或MySQL的不同,同时采用同步和半同步复制。

        2. …对裸机实例而言这似乎是件小事

          EC2本地NVMe加密密钥采用临时机制虽能防范泄露,但对其他云平台并非必需(且不利于恢复能力,可能显著降低业务连续性评分)。以他们收取的费用来看,我期待即使在重启后也能保持相对安全性

          1. 甚至裸机服务器搭配冗余NVMe SSD运行数据库也行

      2. Postgres这类数据库早有成熟方案处理此类问题。若自行搭建数据库,备份本就是必需操作,还需在不同服务器部署副本。

        1. 备份无法解决持久性问题,读副本(异步)同样如此。

          我认为唯一可行的方案是实现类似Planetscale的同步复制,但这相当艰巨。

      3. 某些服务商(如Hetzner)的专用服务器默认配备双RAID 1磁盘阵列,因此故障概率极低(除非数据中心发生火灾)。

        1. 有法国来电,某家OVH公司正在拨打!

          1. 你的备份也会灰飞烟灭。

            我绝不会把重要数据或服务器托付给OVH,毕竟我们都目睹过他们数据中心的“安全措施”——整栋楼着火时,他们花了3小时才切断电源。

      4. 是的,VPS或云服务商中的单个磁盘确实存在耐久性问题。正因如此,EBS这类伪装成单磁盘的产品实际上由多个磁盘组成。不过我们并未依赖多个块设备,而是通过更高层级的冗余机制实现:采用多台MySQL或Postgres服务器保障耐久性,每台服务器都配备本地NVMe驱动器以提升性能。

      5. 确实如此。在一定程度上。若运行关键任务型应用,则绝对如此。

        但多数应用在本地存储上运行良好,且能承受一定停机时间。性能提升甚至可能带来益处。您也可通过配置RAID/ZFS并保持完善备份来解决耐久性与灾难恢复问题。

      6. 没错,PlanetScale总爱炫耀其速度优势,但核心原因在于他们比其他云服务商运行更少的完整抽象层,这确实存在取舍。

        1. 减少抽象层有什么问题?我们清楚其弊端。结果摆在眼前,客户显然青睐这种模式。我们在临时计算环境中安全运行海量状态数据——这才是真正的实力展示。Timescale团队除了抱怨毫无建树。要么写代码,要么闭嘴。

          1. 我完全不批评你们的工程方案。单节点运行确实有优势,你们的基准测试也证明了这点,但这并非同等条件下的比较——还存在其他权衡因素。我只是赞赏社区能指出这些问题。

            另外,这里是HN而非推特,我觉得我们可以更文明些。CEO因无害评论如此动怒,在我看来实在有失体面。

            1. 我们运行的是3个节点而非1个。你的评论并非孤例——即便我们根本没考虑你们,Timescale团队也总在暗讽我们。

      7. 单盘方案确实存在耐久性隐患。但VPS与独立服务器之争我实在看不出多大意义。

      8. 顺便提一句,RAID也不是万能解。在AWS和GCP环境中,即便堆砌再多RAID阵列,一旦CPU或内存故障,本地NVMe驱动器同样会失效。

      9. 我们已通过多重方案缓解了耐久性问题。

    2. 正确。网络存储能灵活适配多种场景,因此PlanetScale同时支持两种方案。

  4. 我的理解是否正确:若运行在NVMe环境下——其速度如此之快,选择何种模式其实无关紧要?

    1. 我通过分析图表也得出了相同结论。

      我认为更优的IO规划仅对18版本中的“低速”I/O有价值。

      相信这将带来大量经验积累。Postgres开发者团队非常出色。

  5.     > IOPS: 3,000
        > IOPS: 300,000(月费551美元)
    

    云服务简直离谱。

    仅供参考:用4块消费级NVMe组建RAID10并接PCIe x16接口,单次成本约1000美元就能轻松实现300万IOPS

    在当前工作中,我们不得不不断重构数据库查询/设计方案,只因云端IOPS限制,更别提无法掌控RDS页面缓存和Numa架构。

    每当深夜被惊醒——某条看似正常的查询突然突破IOPS预算导致WAL日志崩溃时,我总会深刻质疑自己的选择。

    整个云计算生态简直荒谬至极。

    1. 你购买RDS并非因为在意IOPS,而是为了将备份和复制问题转嫁给他人。更重要的是(这里指的可能是你上级的MBA管理层而非你本人),你们更关注将其列为运营支出而非资本支出,远胜于成本本身。当然,ISO审计的合规要求也是原因之一。

      1. 若想将自有硬件转为运营支出,直接租赁即可。所有企业级硬件供应商都会提供此类方案。

      2. > 你为此付费,是因为希望备份和复制成为别人的问题。

        或者直接采用CockroachDB、YugabyteDB等自动复制、节点故障自动重平衡的数据库,它们还内置了S3备份功能…

        若你更倾向亲力亲为,由MySQL Vitess开发者打造的Multigress项目似乎即将完成(https://github.com/multigres/multigres)。

        认为管理软硬件很困难的想法很可笑,但人们(似乎主要是管理者)却认为这是最佳方案。

        1. 我不会说它接近完成——根据其代码库显示,项目仍处于非常早期的开发阶段。目前尚未发现任何证据表明他们甚至能通过该工具运行单条查询。

          即便完成后,运行起来仍需大量工作。当然,这未必困难,但若非核心业务且能盈利,让他人代劳能让你专注于真正重要的事。

    2. 将月度云服务成本与一次性硬件采购成本相比较,完全忽略了后者长期涉及的人力、备件、电力、机房及配件等开销。虽然我承认自建硬件确实能大幅降低成本,但在决策前仍需权衡诸多因素。

      1. 天哪!这已被证明不可能实现,无人能指挥计算机行事

        lspci仅记载于古老炼金术典籍,是三圣赫尔墨斯的秘语低语。

        附注:我亲手扑灭过数据中心的真实火灾,比起这3000 IOPS的垃圾,我更怀念那份实干。

      2. 2000年代末在IT行业工作时,服务器机房仍很常见。即便大型机构分设数百公里外的多个站点,仅需小团队就能管理。据我所知,如今构建高可用应用比当年容易得多。

        云成本已高到让我准备抽身而退,长期计划是回归自有服务器,将节省的资金投入人力。我预见云服务只会越来越贵,绝无降价可能。

        1. 当前正出现向物理基础设施回流的早期趋势。部分源于成本考量(1),部分出于地缘政治顾虑,部分则因性能需求。然而物理设备的管理确实需要企业应对另一套(虽显陈旧但已逐渐萎缩)的技能体系与成本结构。

          (1) 令人震惊的是,当初推动企业迁移云端的主力竟是会计部门——他们追求运营支出而非资本支出,如今却因现金流压力考虑回迁。云服务在提供网页内容和海量数据存储方面表现优异,但一旦涉及数据处理或迁移,成本便会急剧攀升。

          1. 某些机构的云迁移由财务部门主导,而我们机构则是法律部门推动。随着《通用数据保护条例》生效在即,加之其他数据隐私法规可能(但未强制)要求数据存储于客户所在司法管辖区,我们必须在更多区域部署服务器。

            我们拥有两座大型数据中心,但均位于美国。在欧盟地区仅有一间小型服务器机房作为基础设施。巴西、中国等地完全没有托管能力。多区域可用性迫使我们转向云端——但并非出于“高可用性”的考量。

        2. > 我只看到云服务成本持续攀升,绝无下降可能。

          当三大超大规模云服务商激烈竞争时,这种观点基本站不住脚,也不符合市场规律…除非他们开始串通定价。

          正因这种竞争态势,三大供应商的网络服务成本已呈现下降趋势。

        3. 届时云服务将如此优质廉价,你会惊叹“天啊,我能以远低于AWS的价格出售闲置计算资源”。然后我会买下这些资源,你将成为新的云服务商。随后更多人效仿,最终这片服务器基础设施业务将远超你原有主业规模。十年后又会有人抱怨你的IOPS定价,开始自建服务器机房。

      3. 根本无需如此,租用专用服务器即可,成本仍低20-50倍,问题迎刃而解。

    3. 我用过的多数云平台都支持创建带本地磁盘的虚拟机,这可能比网络磁盘更划算。

      1. 帖子描述的是每月500美元的方案,拥有惊人的30万IOPS;而网络磁盘每月1500美元仅提供1.6万IOPS

        更不用说还得自行处理备份、快照、复制等管理难题

    1. 18版的文档也显示该功能,你从何得出18版不可用的结论?

      1. 啊,是我搞错了,我链接的是pg_dump的文档(该命令长期支持format选项),而非pg_dumpall(该命令不支持该选项)。

        在 Postgres 18 发布之前,文档曾将 `format` 列为即将推出的 18 版中 `pg_dumpall` 的选项(例如 2025 年 6 月的互联网档案馆记录 https://web.archive.org/web/20250624230110/https://www.postg…)。相关提交日期为2025年4月(见我原始评论中的链接#0)。但如今所有提及内容均已被清除,甚至开发分支文档中也未保留。

  6. 现在是否有方法避免双缓冲并直接使用PostgreSQL的直接I/O?

    有人认真测试过性能差异吗?

    我认为在该设置下I/O配置不会产生影响,但出于好奇想了解——毕竟这是Oracle和Sybase的默认方案。

  7. 我目前使用bitnami/postgresql:17.6.0-debian-12-r4在Docker容器中运行PostgreSQL。据我所知,Bitnami已停止支持和更新其Docker容器。请问升级到Docker版PostgreSQL 18有何推荐方案?

    初步观察官方Postgres容器发现:- POSTGRESQL_DATABASE 已重命名为 POSTGRESQL_DB– 卷挂载路径当前为 /bitnami/postgresql

  8. 我正在升级生产数据库到pg18版本。该数据库约6TB,每秒处理数千次查询,是否应该考虑使用'worker'模式替代'io_uring'模式?

    1. 既然尚未明确所有变更内容及配置参数,为何要迁移生产数据库?

    2. 对于本就风险较高的升级操作,我建议尽量减少变量数量。待升级完成并稳定后,可将io_method参数切换至新模式的副本实例进行测试,确认无误再切换主实例。

  9. 感谢分享这篇有趣的文章!不知是否也支持timescale扩展?

    1. 是指timescaledb吗?还是其他方案…?

      1. 是的,就是指 timescaledb。抱歉之前没说明白。

  10. 图表效果真棒,想知道用了哪个库实现的。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: