WAIT
等待 WAL 达到目标 LSN
English manual coverage begins with PostgreSQL 6.4. Source history and runtime observations have their own recorded version boundaries.
Reading PG 20·Select a recorded version
This definition is unavailable in the selected language. The original Simplified Chinese text is shown.
- anchor
- SQL-WAIT
- file
- sql-wait.html
- lang
- zh
- name
- WAIT
- purpose
- Unknown
- purpose zh
- 等待 WAL 达到目标 LSN
- sections same as
- Unknown
- slug
- devel
- synopsis text
- WAIT FOR LSN 'lsn' [ WITH ( option [, ...] ) ] 其中 option 可以是: MODE 'mode' TIMEOUT 'timeout' NO_THROW 而 mode 可以是: standby_replay | standby_write | standby_flush | primary_flush
Syntax
WAIT FOR LSN 'lsn'
[ WITH ( option [, ...] ) ]
其中 option 可以是:
MODE 'mode'
TIMEOUT 'timeout'
NO_THROW
而 mode 可以是:
standby_replay | standby_write | standby_flush | primary_flushSyntax diagrams
Read left to right. Branches are choices, bypasses are optional, loops repeat. Select an underlined parameter to open its rule.
option
mode
Definition PG 20
WAIT FOR LSN 'lsn' [ WITH ( option [, ...] ) ] 其中 option 可以是: MODE 'mode' TIMEOUT 'timeout' NO_THROW 而 mode 可以是: standby_replay | standby_write | standby_flush | primary_flush
描述
等待直到根据指定的 mode 达到指定的 lsn,该模式决定等待 WAL 被写入、刷盘还是重放。如果没有指定 timeout,或者其值为零,则此命令会无限期等待 lsn。
超时时会发出错误,除非在 WITH 子句中指定了 NO_THROW。对于备库模式(standby_replay、standby_write、standby_flush),如果在达到 lsn 之前服务器被提升,也会发出错误。如果指定了 NO_THROW,命令会以状态字符串报告这些结果,而不抛出错误。
可能的返回值是 success、timeout 和 not in recovery。
参数
lsn指定要等待的目标 LSN。
WITH (option[, ...] )此子句指定等待操作的可选参数。支持以下参数:
MODE'mode'指定要等待的 LSN 处理类型。如果未指定,默认值为
standby_replay。有效模式如下:standby_replay:等待该 LSN 在备库上被重放(应用到数据库)。成功完成后,pg_last_wal_replay_lsn()将返回大于或等于目标 LSN 的值。此模式只能在恢复期间使用。standby_write:等待包含该 LSN 的 WAL 被写入备库磁盘,但不一定已经刷盘。这比standby_flush更快,但持久性保证更弱,因为数据可能仍在操作系统缓冲区中。备库上已有的 WAL(来自基础备份、归档恢复或先前的流式传输)以及从主库新接收的 WAL 均可满足此条件。此模式只能在恢复期间使用。standby_flush:等待包含该 LSN 的 WAL 在备库上刷盘。这提供了持久性保证,而无需等待 WAL 被应用。备库上已有的 WAL(来自基础备份、归档恢复或先前的流式传输)以及从主库新接收的 WAL 均可满足此条件。此模式只能在恢复期间使用。primary_flush:等待包含该 LSN 的 WAL 在主库上刷盘。成功完成后,pg_current_wal_flush_lsn()将返回大于或等于目标 LSN 的值。此模式只能在主库上使用(不能在恢复期间使用)。
TIMEOUT'timeout'在指定且
timeout大于零时,命令会一直等待到lsn达到,或者直到指定的timeout到期为止。值为零(默认值)表示命令会无限期等待。timeout是以毫秒为单位的时长。也可以将其指定为一个字符串,其中包含数值及其后的时间单位(见第 19.1.1 节)。最大值为2147483647 ms。小数值会舍入到最接近的毫秒数。因此,注意半毫秒或更短的
timeout会向下舍入为零,这意味着无限期等待。NO_THROW指定在超时或在主库上运行时不抛出错误。在这种情况下,可以从返回值中获取结果状态。
当
timeout或not in recovery是应用程序预期并打算处理的结果时,可使用此选项,例如重试等待、报告复制延迟,或为后续操作选择另一台服务器。命令随后会将结果作为状态返回;应用程序必须检查该状态,才能认定已达到目标 LSN。如果应用程序必须在达到目标 LSN 后才能继续,则应省略此选项,这样等待未成功时就会通过错误停止正常执行。返回状态也会使显式事务保持可用;如果不使用此选项,相应错误会要求先回滚事务,或回滚到保存点,才能发出后续命令。
此选项只改变
timeout和not in recovery的报告方式。其他错误仍会抛出,包括无效输入(例如格式错误的 LSN 或无法识别的选项值),以及等待开始前检查的所有条件(例如在恢复期间请求primary_flush,或在持有锁的同时等待备库 LSN)。此选项也不限制等待时长;要限制时长,应指定TIMEOUT。
输出
success此返回值表示已成功达到目标
lsn。timeout此返回值表示在达到目标
lsn之前发生了超时。not in recovery此返回值表示数据库服务器不处于恢复状态。这可能意味着数据库服务器在接收到命令时并不处于恢复状态(即在主库上执行),也可能意味着它在达到目标
lsn之前被提升。在提升的情况下,此状态表示发生了时间线变更,应用程序应重新评估目标 LSN 是否仍然适用。
注解
WAIT 必须作为顶层命令执行,不能从函数、过程或 DO 块中执行。当前事务持有快照时也不能执行。WAIT 本身不获取快照,因此可以在 REPEATABLE READ 或 SERIALIZABLE 事务中第一条获取快照的语句之前运行,但不能在该语句之后运行;无论处于何种隔离级别,如果游标或导出的快照使事务持有快照,也不能运行。此处持有的快照可能延迟重放,而 standby_replay 会等待重放,其他备库模式最终也可能需要等待重放。这也是 WAIT 被实现为命令而不是函数或过程的原因,因为函数和过程执行时会持有快照。
恢复进行期间,如果会话已经持有锁,且尚未达到目标 lsn,则会拒绝 standby_replay(默认值)、standby_write 或 standby_flush 模式的等待。这样的锁可能使启动进程直接或通过另一个会话等待当前会话,而当前会话又在等待启动进程推进恢复。这个循环在当前会话一侧不涉及锁等待,因而死锁检测无法发现,也没有机制可以打破它。如果已经达到目标,等待会立即返回,因此始终允许。
应在事务块之外发出 WAIT FOR,或将其作为事务块的第一条语句,在运行任何会获取锁的操作之前执行。这也是下文示例所示读己之写模式的自然顺序:先等待目标 lsn,再运行必须看到相应更改的查询。注意,在 READ COMMITTED 下,即使先前语句的快照已经释放,它获取的锁仍会保留。因此,即使隔离级别允许等待,在这类语句之后执行等待仍会被拒绝。
此限制也适用于 standby_write 和 standby_flush,尽管流复制可以在不依赖启动进程的情况下推进这两个位置。这两个位置都不会落后于重放位置,因此当 walreceiver 未处于活动状态时,重放可能是推进它们的唯一途径。如果所持有的锁阻塞了重放,会话就在等待重放推进,而重放又在等待会话释放锁。在流复制下,只有 WAL 持续到达时,这些位置才会独立推进。如果接收在达到目标之前停止,被阻塞的启动进程就无法重新启动 walreceiver。它也无法重放推进重启点和回收 WAL 所需的较新检查点记录,因此 pg_wal 可能被填满,导致接收在达到目标之前停止。所以,即使等待开始时流式传输处于活动状态,此限制也仍然适用。
WAIT 会根据指定的 mode 一直等待直到达到指定的 lsn。standby_replay 模式会等待该 LSN 被重放(应用到数据库),这有助于在使用异步副本读取和主库写入时实现读己之写一致性,前提是目标 LSN 位于主库上相关写事务的 COMMIT 记录末尾或其后。standby_flush 模式会等待 WAL 在副本上刷入持久存储,或者等待备库上已有的 WAL 已被重放。standby_write 模式会等待 WAL 被写入操作系统,或者已经重放;对于新接收的 WAL,这比刷盘更快,但持久性保证更弱。primary_flush 模式会等待 WAL 在主库上刷盘。在所有情况下,最后一次修改的 LSN 应当存储在客户端应用程序一侧或连接池一侧。
备库模式(standby_replay、standby_write、standby_flush)只能在恢复期间使用,而 primary_flush 只能在主库上使用。对当前服务器状态使用错误的模式会导致错误。如果在使用备库模式等待期间备库被提升,命令将返回 not in recovery(或者在未指定 NO_THROW 时抛出错误)。提升会创建新的时间线,而正在等待的 LSN 可能指向旧时间线中的 WAL。
WAIT只比较LSN数值;它并不知道 WAL 记录属于哪条时间线。当备库跨上游时间线切换继续恢复时,这一点很重要—例如,级联备库的上游被提升。在这种情况下,只要所选等待模式使用的位置达到或超过该LSN数值,WAIT就会返回success,而不考虑该 LSN属于哪条时间线。需要确认目标指向预期时间线的应用程序必须自行验证时间线。
在备库服务器上,WAIT 会话可能会被恢复冲突中断。某些恢复冲突是不可避免的:例如,重放一个表空间删除操作时,无论后端正在执行什么,都会通过终止所有后端来解决冲突。在备库上使用 WAIT 的应用程序应准备好处理此类中断,例如通过重试命令或回退到其他机制。
示例
可以使用 WAIT 命令等待 pg_lsn 值。例如,应用程序可以更新 movie 表,并获取位于相关写事务的 COMMIT 记录末尾或其后的 lsn。在这里展示的默认自动提交模式下,UPDATE 会在后续的 SELECT 之前提交。由于 synchronous_commit 可能设置为 off,此示例在主库上使用 pg_current_wal_insert_lsn 获取 lsn。
postgres=# UPDATE movie SET genre = 'Dramatic' WHERE genre = 'Drama'; UPDATE 100 postgres=# SELECT pg_current_wal_insert_lsn(); pg_current_wal_insert_lsn --------------------------- 0/0306EE20 (1 row)
然后,应用程序可以使用提交之后从主库获得的 lsn 运行 WAIT。之后,主库上所做的更改应当保证在副本上可见。
postgres=# WAIT FOR LSN '0/0306EE20'; status --------- success (1 row) postgres=# SELECT * FROM movie WHERE genre = 'Drama'; genre ------- (0 rows)
等待刷盘(数据在副本上持久化):
postgres=# WAIT FOR LSN '0/0306EE20' WITH (MODE 'standby_flush'); status --------- success (1 row)
带超时的等待写入:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (MODE 'standby_write', TIMEOUT '100ms', NO_THROW); status --------- success (1 row)
等待主库刷盘:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (MODE 'primary_flush'); status --------- success (1 row)
如果在超时之前未达到目标 LSN,则会抛出错误:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (TIMEOUT '0.1s'); ERROR: timed out while waiting for target LSN 0/0306EE20 to be replayed; current standby_replay LSN 0/0306EA60
同一个示例使用带 NO_THROW 选项的 WAIT:
postgres=# WAIT FOR LSN '0/0306EE20' WITH (TIMEOUT '100ms', NO_THROW); status --------- timeout (1 row)
Compare versions
Complete source facts
synopsis html
WAIT FOR LSN '<em class="replaceable"><code>lsn</code></em>'
[ WITH ( <em class="replaceable"><code>option</code></em> [, ...] ) ]
<span class="phrase">其中 <em class="replaceable"><code>option</code></em> 可以是:</span>
MODE '<em class="replaceable"><code>mode</code></em>'
TIMEOUT '<em class="replaceable"><code>timeout</code></em>'
NO_THROW
<span class="phrase">而 <em class="replaceable"><code>mode</code></em> 可以是:</span>
standby_replay | standby_write | standby_flush | primary_flushSource references
Full definition and evidence JSON
Definition sources
pgweb · PostgreSQL 20 · 1b5ca64c
Text language: zh-Hans · 1b5ca64c