在PostgreSQL中,synchronous_commit是一个看似不起眼却影响深远的核心参数。它决定了事务提交时WAL(预写日志)是否必须落盘才能向客户端返回成功,直接影响数据安全性和写入性能的平衡。配置不当可能导致数据丢失,也可能白白牺牲一半的写入吞吐。理解它的各个取值及其背后的刷盘机制,是每个DBA和后端开发者的必修课。

一、先搞清楚:事务提交时WAL到底发生了什么
PostgreSQL采用WAL先写日志的原则:数据页的修改先记录到WAL缓冲区,再由检查点或后台进程刷到数据文件。事务提交时,会向WAL写入一条提交记录,而synchronous_commit控制的就是这条提交记录何时真正写到磁盘。
具体流程是这样的:客户端执行COMMIT后,服务端进程产生提交记录并写入WAL缓冲区。如果synchronous_commit开启,进程会调用同步刷盘函数,等待操作系统确认日志已物理写入磁盘,然后才向客户端返回事务成功;如果关闭,提交记录只停留在缓冲区,由后台的WAL Writer进程大约每wal_writer_delay(默认200毫秒)批量刷一次盘,客户端几乎立即得到响应。
这里有个关键点容易被忽略:即使synchronous_commit设为off,数据也不会"丢库",最多丢失最近几百毫秒内已提交事务的变更,数据库实例本身依然一致可启动。PostgreSQL官方文档称之为crash safety与durability的区别,理解这一点是选型的前提。
二、五个同步级别的机制与差异
synchronous_commit共有五个取值,按持久性从弱到强依次是off、local、on、remote_write、remote_apply(在流复制场景下)。下面逐一分析。
1. off:最快但可能丢最近的事务
提交不等WAL落盘,客户端在记录写入缓冲区后就收到成功。单事务延迟极低,吞吐量最高,代价是实例崩溃时可能丢失最多约3倍wal_writer_delay间隔内的提交事务(约600毫秒),注意这个延迟只影响持久性,不会造成数据损坏。
2. local:只保证本地落盘
提交记录必须写入本地磁盘才返回,但不等待任何备库确认。适合单机部署,行为等同于没有流复制时的on。如果配置了同步流复制而设为local,则本地落盘即算成功,备库可能落后。
3. on:默认值,本地加同步备库
默认配置下,提交需等待WAL刷入本地磁盘。若同时配置了synchronous_standby_names,还会等待同步备库确认收到WAL记录(备库收到即可,不必已刷盘),这是最常见的生产配置。
4. remote_write:备库收到且已写入文件系统
要求备库把WAL写到操作系统层面(写入但未fsync到磁盘)。相比on多了一层保障:主库崩溃且磁盘损坏时,只要备库机器还活着,数据仍在。备库断电场景下理论上仍可能丢,但概率大幅降低。
5. remote_apply:最强持久性
等待备库不仅收到WAL,还要完成回放(apply)才返回。这意味着后续的只读查询在备库上一定能看到该事务,是实现读写分离强一致读的唯一选择。代价是延迟最高,因为回放本身需要时间。可用下面的语句观察确认状态:
-- 查看同步备库的确认状态 SELECT application_name, state, sync_state, replay_lag FROM pg_stat_replication; -- 查看当前参数值 SHOW synchronous_commit;
三、典型场景下的选型建议
选型的核心逻辑是:这笔业务丢几百毫秒的数据,代价有多大?下面按场景给出建议。
金融支付与订单交易:资金相关操作必须使用on甚至remote_apply,配合同步流复制部署。宁可牺牲延迟也不能丢交易记录。建议主库用on,同步备库配置一个,必要时再加一个潜在的同步候选。
日志、埋点、监控指标采集:这类数据量大且丢几条不影响大局,off是性价比最高的选择,配合批量写入,吞吐可以提升一倍以上。很多大规模监控系统的写入端都采用这种方式。
读写分离的从库读:如果业务依赖备库读到的数据必须是最新的(例如写后立即读),必须用remote_apply,否则备库读可能读到旧数据引发逻辑错误。
普通业务系统:保持默认的on即可,多数场景不需要改动。不要为了性能盲目关闭它,除非明确评估过丢失风险。
四、会话级动态调整:一个被低估的技巧
synchronous_commit是USERSET级别参数,可以在会话甚至单个事务级别修改。这带来一个非常实用的模式:同一个数据库中,关键操作用强同步,非关键操作关闭同步,互不干扰。
-- 会话级别:本次连接内关闭同步提交 SET synchronous_commit = off; -- 事务级别:只影响当前事务块 BEGIN; SET LOCAL synchronous_commit = remote_apply; INSERT INTO payment_records(amount) VALUES (99.9); COMMIT; -- 恢复默认 RESET synchronous_commit;
这种细粒度控制在实际生产中非常有价值。比如电商系统中,支付流水走remote_apply,而用户行为日志插入走off,两者共用一套数据库却各取所需,避免了全局配置的非此即彼。
另一个常见误区是把synchronous_commit和fsync混淆。fsync是更底层的总开关,控制PostgreSQL是否将数据刷到磁盘,生产环境绝对禁止关闭,否则可能造成数据损坏。而synchronous_commit关闭只影响最近提交事务的可见性持久性,不会损坏数据,两者风险等级完全不同。
最后提醒一点:调整参数前先用pg_test_fsync工具确认磁盘本身的fsync性能。如果磁盘fsync延迟超过1毫秒,先解决硬件或文件系统问题,再谈参数调优,否则任何同步级别的配置都建立在不可靠的地基上。理解业务对数据丢失的容忍度,再对照五个级别做选择,才是正确的思路。
PostgreSQLsynchronous_commit事务提交修改时间:2026-09-09 06:46:35