异步提交 是一种允许事务更快完成的选项,但代价是数据库崩溃时可能丢失最新的事务。在许多应用程序中,这是一个可接受的权衡。
如前一节所述,事务提交通常是 同步 的:服务器在向客户端返回成功指示之前,会等待事务的WAL记录被刷新到永久存储。因此,客户端可以保证报告已提交的事务将被保留,即使服务器在之后立即崩溃。然而,对于短事务来说,这种延迟是总事务时间的主要组成部分。选择异步提交模式意味着服务器在事务逻辑上完成后立即返回成功,而在它生成的WAL记录实际写入磁盘之前。这可以为小型事务提供显著的吞吐量提升。
异步提交引入了数据丢失的风险。在向客户端报告事务完成与事务真正提交(即保证在服务器崩溃时不会丢失)之间有一个短暂的时间窗口。因此,如果不应使用异步提交,客户端将采取外部操作,依赖于事务将被记住的假设。例如,银行绝对不会使用异步提交来记录自动取款机吐出现金的事务。但在许多场景中,例如事件日志记录,就不需要这种强有力的保证。
使用异步提交的风险是数据丢失,而不是数据损坏。如果数据库崩溃,它将通过重放WAL到最后一个已刷新记录来恢复。因此,数据库将恢复到一致的状态,但尚未刷新到磁盘的任何事务将不会反映在该状态中。最终效果是丢失最后几个事务。因为事务是按提交顺序重放的,所以不会引入不一致——例如,如果事务 B 进行了依赖于先前事务 A 的效果的更改,那么 A 的效果不可能在 B 的效果被保留的同时丢失。
用户可以选择每个事务的提交模式,因此可以同时运行同步和异步提交的事务。这允许在性能和事务持久性保证之间进行灵活的权衡。提交模式由用户可设置的参数 synchronous_commit 控制,该参数可以通过任何设置配置参数的方式进行更改。任何一个事务使用的模式取决于事务提交开始时 synchronous_commit
的值。
某些实用命令,例如 DROP TABLE
,无论 synchronous_commit
的设置如何,都会强制同步提交。这是为了确保服务器文件系统与数据库的逻辑状态之间的一致性。支持两阶段提交的命令(如 PREPARE TRANSACTION
)也始终是同步的。
如果在异步提交和事务WAL记录写入之间的风险窗口期间数据库崩溃,那么该事务所做的更改 将 会丢失。风险窗口的持续时间是有限的,因为后台进程(“WAL writer”)每 wal_writer_delay 毫秒将未写入的WAL记录刷新到磁盘。风险窗口的实际最长持续时间是 wal_writer_delay
的三倍,因为 WAL writer 的设计是在繁忙时段优先写入整个页面。
立即模式关机等同于服务器崩溃,因此将导致任何未刷新的异步提交丢失。
异步提交提供的行为不同于设置 fsync = off。 fsync
是一个服务器范围的设置,它会改变所有事务的行为。它禁用了 PostgreSQL 中试图将写操作同步到数据库不同部分的所有逻辑,因此系统崩溃(即硬件或操作系统崩溃,而不是 PostgreSQL 本身失败)可能导致数据库状态任意严重损坏。在许多场景中,异步提交提供了通过关闭 fsync
所能获得的大部分性能提升,而没有数据损坏的风险。
commit_delay 听起来也非常类似于异步提交,但它实际上是一种同步提交方法(事实上,在异步提交期间会忽略 commit_delay
)。 commit_delay
会在事务刷新WAL到磁盘之前延迟一段时间,希望能有一个事务执行的单个刷新也可以服务于大约同时提交的其他事务。该设置可以被认为是增加事务可以加入即将参与单个刷新的组的时间窗口的一种方式,以分摊多个事务的刷新成本。
如果您在文档中发现任何不正确、与您在使用特定功能时的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。