PostgreSQL中的选择性异步提交——平衡持久性和性能
Selective async commits in PostgreSQL – balancing durability and performance

原始链接: https://www.shayon.dev/post/2025/75/selective-asynchronous-commits-in-postgresql-balancing-durability-and-performance/

PostgreSQL的`synchronous_commit`设置控制事务的持久性。默认设置确保数据写入磁盘后才确认事务,保证在崩溃时不会丢失数据。但是,这可能会导致I/O密集。 异步提交(`synchronous_commit = off`)通过在WAL记录刷新之前确认事务来提高性能(在某些情况下TPS最多可提高30%),减少I/O和CPU负载。但这会产生一个“风险窗口”,在此窗口内,最近的事务可能会在崩溃时丢失。 一个关键优势是选择性应用。`synchronous_commit`可以根据会话、事务或操作进行切换,从而能够优化非关键操作,同时保持关键数据的完整持久性。示例中提供了Ruby on Rails代码片段。 PostgreSQL提供了诸如'remote_write'和'local'之类的中间设置,以平衡性能和持久性。然而,在像Aurora PostgreSQL这样的环境中,'off'设置通常能提供最显著的性能提升。请仔细权衡利弊,因为此设置会影响数据丢失的风险。

Hacker News 最新 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 PostgreSQL 中的选择性异步提交 – 平衡持久性和性能 (shayon.dev) 7 分,由 shayonj 发帖,2 小时前 | 隐藏 | 过去 | 收藏 | 讨论 加入我们,参加 6 月 16-17 日在旧金山举办的 AI 初创公司学校! 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系我们 搜索:

原文

I was recently looking into some workloads that generate a lot of I/O and CPU contention on some very high-write code paths and came across synchronous_commit (https://www.postgresql.org/docs/current/wal-async-commit.html). It can be very tempting to turn this off globally because the performance gains in terms of I/O, CPU, and TPS (transactions per second) are very hard to overlook. I noticed I/O completely gone, CPU down 20% (at peak), and a 30% increase in TPS. However, this comes with important trade-offs that are worthwhile keeping in mind.

What is Synchronous Commit?

By default, PostgreSQL uses synchronous commit, meaning when your application commits a transaction, PostgreSQL:

  1. Writes the transaction’s changes to the Write-Ahead Log (WAL)
  2. Flushes those WAL records to permanent storage
  3. Only then acknowledges success to the client

This ensures durability - if the database crashes immediately after a commit, your transaction is still safe. However, this disk I/O operation is often the bottleneck for transaction throughput, especially for small, frequent transactions.

Enter Asynchronous Commit

Asynchronous commit changes this behavior. When enabled, PostgreSQL acknowledges transaction success immediately after the transaction is logically complete, before WAL records are flushed to disk.

-- Enable asynchronous commit
SET synchronous_commit = off;

-- Back to default (synchronous)
SET synchronous_commit = on;

The result? Significantly improved transaction throughput and reduced I/O pressure. In my testing, this simple change has increased transactions per second by 30%, especially on I/O-constrained systems.

The Trade-off: Understanding the Risk Window

The performance gain comes with a trade-off: a small “risk window” between when a transaction is reported as committed and when it’s actually written to disk. If the database server crashes during this window, the most recent transactions could be lost, and this is where it feels wrong to turn on this setting globally. The risk here is data loss, not corruption. PostgreSQL documentation explains this nicely in very plain terms: https://www.postgresql.org/docs/current/wal-async-commit.html

Selective Implementation

Even after testing other settings of synchronous_commit, I’ve found the beauty of this feature is that you don’t have to make a global all-or-nothing choice. You can toggle it:

  • Per session
  • Per transaction
  • For specific operations

This allows for a nuanced approach where critical transactions remain fully durable while less critical operations get performance boosts.

In Ruby on Rails applications, it can be as simple as doing something like this:

def with_synchronous_commit_off(&block)
  ActiveRecord::Base.connection.exec_query("SET synchronous_commit = off")
  yield
ensure
  ActiveRecord::Base.connection.exec_query("SET synchronous_commit = on")
end

with_synchronous_commit_off do
  # Perform non-critical bulk operations here
  # e.g., analytics data, logs, or background processing
end

PostgreSQL offers more than just on/off for synchronous_commit. There are intermediate settings that provide different balances of performance and durability:

-- Options from strongest guarantee to highest performance:
SET synchronous_commit = 'remote_apply'; -- Strongest guarantee (for replicas)
SET synchronous_commit = 'remote_write'; -- Strong but faster
SET synchronous_commit = 'local';        -- Local durability only
SET synchronous_commit = 'off';          -- Maximum performance

However, at least on Aurora PostgreSQL, I’ve found the maximum benefit from setting it to OFF. I reckon, due to the way Aurora works and its requirement that 4 out of 6 nodes need to acknowledge a commit (https://aws.amazon.com/blogs/database/amazon-aurora-postgresql-parameters-part-2-replication-security-and-logging/), the rest of the settings may not be doing much or their benefits might get amortized.

Wrap up

I realize this might be a very well-known setting amongst seasoned PostgreSQL users. That said, I hope you found this post useful, and I’d love to hear about your experiences using synchronous_commit in production.

联系我们 contact @ memedata.com