Postgresql 中文操作指南
30.4. Asynchronous Commit #
Asynchronous commit 允许事务更快完成,代价是,如果数据库崩溃,则最近的事务可能会丢失。在许多应用程序中,这是一个可接受的权衡。
如前一节中所述,事务提交通常是 synchronous:服务器等待将事务的 WAL 记录刷新到永久存储,然后向客户端返回成功指示。因此,即使在服务器立即崩溃的情况下,客户端也可以保证报告已提交的事务将会保留。然而,对于短事务,此延迟是总事务时间的主要组成部分。选择异步提交模式意味着服务器在生成的 WAL 记录实际上到达磁盘之前,就会在事务逻辑完成时返回成功。这可以为小型事务大大提升吞吐量。
异步提交引入了数据丢失风险。在向客户端报告事务完成和事务真正提交(即,保证在服务器崩溃时不会丢失)之间存在一个较短的时间窗口。因此,如果客户端将根据事务将被记住的假设采取外部操作,则不应当使用异步提交。举例来说,银行肯定不会针对记录 ATM 发放现金的事务使用异步提交。但是在许多场景(例如事件日志记录)中,不需要这种强有力的保证。
使用异步提交承担的风险是数据丢失,而不是数据损坏。如果数据库崩溃,它将通过重放到最后一次刷新的记录的 WAL 来恢复。因此,数据库将恢复为自洽状态,但任何尚未刷新到磁盘的事务将不会反映在该状态中。因此,净结果是丢失最后几个事务。因为按提交顺序重放事务,所以不会引入任何不一致性,例如,如果事务 B 根据先前事务 A 的结果进行更改,而 A 的结果在保留 B 的结果时丢失,则不可能。
用户可以选择每项事务的提交模式,这样可以同时运行同步提交事务和异步提交事务。这使得在性能和交易耐用性的确定性之间做出灵活的权衡成为了可能。提交模式由可通过设置配置参数的任何方式进行更改的用户可设置参数 synchronous_commit 控制。对任何一项事务使用的模式取决于事务提交开始时的 synchronous_commit 值。
某些实用程序命令,例如 DROP TABLE,强制同步提交,无论 synchronous_commit 的设置如何。这是为了确保服务器文件系统和数据库的逻辑状态之间的一致性。支持两阶段提交的命令,例如 PREPARE TRANSACTION,也总是同步的。
如果数据库在异步提交和写入事务 WAL 记录之间的风险窗口期间崩溃,则在该事务期间做出的更改 will 将丢失。风险窗口的持续时间有限,因为一个后台进程(“WAL 编写器”)将未写入的 WAL 记录每 wal_writer_delay 毫秒刷新到磁盘。风险窗口的实际最长持续时间为 wal_writer_delay 的三倍,因为 WAL 编写器设计为在繁忙期间一次写入整个页面。
Caution
立即模式关闭等效于服务器崩溃,因此将导致丢失任何未刷新的异步提交。
不同步提交提供不同的行为,但不关闭 fsync。_fsync_是整个服务器的设置,它将改变所有事务的行为。它会禁用 PostgreSQL 中试图将写同步到数据库的不同部分的所有逻辑,因此系统崩溃(即硬件或操作系统崩溃,并非 PostgreSQL 本身故障)可能会导致数据库状态任意地严重损坏。在许多场景中,不同步提交提供的大部分性能提升是通过关闭 _fsync_获得的,但不具有数据损坏风险。
commit_delay听起来也和不同步提交非常类似,但它实际上是一个同步提交方法(事实上,在不同步提交期间 commit_delay 被忽略)。_commit_delay_会在事务将 WAL 冲洗到磁盘之前造成延迟,期望一次冲洗操作执行在一个事务中时也能为几乎同时提交的其他事务服务。该设置可以被视为一种增加时间窗口的方式,事务可以在该时间窗口中加入一个打算参与单次冲洗操作的组,以便在多个事务之间冲抵冲洗成本。