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