Skip to content

30.4. 异步提交#

异步提交是一种选项,它允许事务更快速地完成,但代价是如果数据库崩溃,最近的事务可能会丢失。在许多应用程序中,这是一个可以接受的权衡。

如前一节所述,事务提交通常是同步的:服务器等待事务的WAL记录刷新到永久存储,然后向客户端返回成功指示。因此,可以保证向客户端报告已提交的事务将被保留,即使在服务器立即崩溃的情况下也是如此。但是,对于短事务,此延迟是总事务时间的主要组成部分。选择异步提交模式意味着服务器在事务逻辑完成时立即返回成功,而无需它生成的WAL记录实际写入磁盘。这可以显著提高小事务的吞吐量。

异步提交引入了数据丢失的风险。从向客户端报告事务完成到事务真正提交(即,如果服务器崩溃,则保证不会丢失)之间有一个短暂的时间窗口。因此,如果客户端将采取依赖于事务将被记住的假设的外部操作,则不应使用异步提交。例如,银行肯定不会对记录 ATM 机发放现金的事务使用异步提交。但在许多情况下,例如事件记录,不需要这种强有力的保证。

使用异步提交所承担的风险是数据丢失,而不是数据损坏。如果数据库崩溃,它将通过重放WAL(直到最后一条已刷新的记录)来恢复。因此,数据库将恢复到自洽状态,但尚未刷新到磁盘的任何事务将不会反映在该状态中。因此,净效应是丢失最后几个事务。由于事务按提交顺序重放,因此不会引入任何不一致性——例如,如果事务 B 根据先前事务 A 的影响进行更改,则不可能在保留 B 的影响的同时丢失 A 的影响。

用户可以选择每个事务的提交模式,以便同时运行同步和异步提交事务。这允许在性能和事务持久性的确定性之间进行灵活的权衡。提交模式由用户可设置的参数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刷新到磁盘之前造成延迟,希望由一个这样的事务执行的单个刷新也可以为大约在同一时间提交的其他事务提供服务。该设置可以被认为是增加事务可以加入即将参与单个刷新的组的时间窗口的一种方式,以便在多个事务之间摊销刷新的成本。