29.3. 异步提交

异步提交是一个可以加快速事务完成的选项,如果数据库崩溃时,最新的信息可能会丢失。 在大多数应用中这个是均衡的。

在前一个章节的描述,事务提交一般是同步的:在对客户端成功运行一个指示之前, 服务器等待事务的WAL记录对存储的刷新。即使在服务器崩溃后, 客户端依然会保证报告提交的事务将会保存。尽管,对于简短的事务,延迟对与整个 事务时间来说是一个主要的部分。选择异步提交模式意味着,在其产生WAL记录成功转到磁盘之前, 一旦事务在逻辑上完成后服务端将会返回成功。这样对事务的吞吐量可以提供一个显著的提高。

异步提交介绍了数据丢失的风险。这是在向客户端报告事务完成的时间点和实际执行客户端的时间点之间的一个很小的时间窗口 (即,保证如果服务器崩溃时不会丢失)。因此如果客户端采取外部动作(前提是假设事务会被记下),此时不应使用异步提交。 例如,一个银行肯定不会为一个ATM分配现金的事务使用异步提交。但在多数情况下,如事件日志记录,不需要这种强力保证。

使用异步提交的风险在于数据丢失,而不是数据损坏。如果数据库崩溃,那么它会根据刷入的最新的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写进程被设计为支持在繁忙时 一次写入所有块。

Caution

IMMEDIATE模式的关闭等同于服务器崩溃,因此会造成哪些未刷入的异步提交的数据丢失。

异步提交不同于设置fsync = off。 fsync是一个用于更改所有事物的行为的服务器端设置。 它会禁用PostgreSQL中尝试向数据库不同部分同步写入的逻辑, 因此,一次系统崩溃(停电或操作系统崩溃,而不是PostgreSQL本身出问题)会导致 数据库状态不可预知的崩溃。在多数情况下,通过关闭fsync,异步提交会提高性能, 不会有数据崩溃的风险。

看起来,commit_delay与异步提交很相似,但实际上它是一种异步提交方法 (事实上,异步提交时会忽略commit_delay)。 在一次异步提交尝试向磁盘刷入WAL之前,commit_delay会造成延迟, 希望在一个这样的事务中执行一个单独的刷入可以用于同一时间的其他事务提交。 当存在不一致提交事务时,设置commit_delay也是有用的, 很难调整到一个实际上是帮助而不是伤害吞吐量的值。