深度解析 PostgreSQL Protocol v3.0(三)— 流复制(上)-02 复制命令

时间:2024-07-14 07:05:39

当需要启动流复制时,客户端端会在 StartupMessage 消息中发送 replication 参数。replication 参数的布尔值 true(或 on,yes,1)告诉服务器端进入物理复制 Walsender 模式,其中可以发出如一小组复制命令,而不是 SQL 语句。

如果 replication 参数的值设置为 replication=database,会指示服务器端进入逻辑复制 Walsender 模式,连接到 dbname 参数中指定的数据库。在逻辑复制 Walsender 模式中,可以发出复制命令以及普通的 SQL 命令。在物理复制或逻辑复制 Walsender 模式中,只能使用简单的查询协议。

为了测试复制命令,可以使用带有包括 replication 选项的连接字符串的工具,通过 psql 或任何其他 libpq 驱动建立复制连接。例如,建立逻辑复制连接:

  1. Shell
  2. psql “dbname=postgres replication=database” -c “IDENTIFY_SYSTEM;”

但是,使用 pg_receivewal(用于物理复制)或 pg_recvlogic(用于逻辑复制)工具通常更有用。如果连接中 log_replication_commands 启用时,复制命令会记录在服务器日志中。

在复制模式下可以接受的命令包括以下 8 种:IDENTIFY_SYSTEM、SHOW name、TIMELINE_HISTORY、CREATE_REPLICATION_SLOT、START_REPLICATION、START_REPLICATION LOGICAL、DROP_REPLICATION_SLOT、BASE_BACKUP。

(1)IDENTIFY_SYSTEM

请求服务器标识自己。服务器使用单行的结果集进行回复,该结果集包含四个字段:

  • systemid (text):标识集群的唯一系统标识符。使用该字段可以检查用于初始化待命状态的基础备份是否来自同一集群。
  • timeline (int4):当前时间线 ID。也可以用于检查待命状态是否与主集群状态一致。
  • xlogpos (text):当前 WAL flush 位置。用于在 WAL 中获取可以启动流的已知位置。
  • dbname (text):连接的目标数据库。可以为 null。

(2)SHOW name

name:运行时参数的名称。支持的参数名称此处不再赘述,参考服务器配置。

请求服务器发送运行时参数的当前设置值。类似于 SQL 命令 SHOW。

(3)TIMELINE_HISTORY

完整命令为:

  1. TIMELINE_HISTORY tli

请求服务器发送覆盖时间线 tli 的时间线历史文件。服务器使用单行的结果集进行回复,该结果集包含两个字段。字段被标记为 text,但它们有效地返回原始字节,无需编码转换:

  • filename (text):时间线历史文件的文件名,例如 00000002.history。
  • content (text):时间线历史文件的内容。

(4)CREATE_REPLICATION_SLOT

完整命令为:

  1. CREATE_REPLICATION_SLOT slot_name [ TEMPORARY ] { PHYSICAL [
    RESERVE_WAL ] | LOGICAL output_plugin [ EXPORT_SNAPSHOT |
    NOEXPORT_SNAPSHOT | USE_SNAPSHOT ] }

创建物理或逻辑复制插槽。关于复制插槽此处不再赘述,详细信息可以参考复制插槽。
slot_name:要创建的插槽的名称。必须是有效的复制插槽名称,它可以包含小写字母、数字和下划线。

  • output_plugin:用于逻辑解码的输出插件的名称。详情可以参考逻辑解码输出插件。
  • TEMPORARY:指定此复制插槽为临时插槽。临时插槽不会保存到磁盘,并且会在出现错误或会话结束时自动删除。
  • RESERVE_WAL:指定此物理复制插槽立即保留 WAL。否则,WAL 仅在从流复制客户端连接时保留。
  • EXPORT_SNAPSHOT, NOEXPORT_SNAPSHOT,
    USE_SNAPSHOT:决定如何处理在逻辑插槽初始化期间创建的快照。EXPORT_SNAPSHOT
    是默认值,它将导出快照以便在其他会话中使用。此选项不能在事务内部使用。USE_SNAPSHOT
    将为执行该命令的当前事务使用快照。此选项必须在事务中使用,并且 CREATE_REPLICATION_SLOT
    必须是该事务中运行的第一个命令。最后,NOEXPORT_SNAPSHOT 将正常使用快照进行逻辑解码,但不会对其执行任何其他操作。

作为对 CREATE_REPLICATION_SLOT 命令的响应,服务器将发送一个包含以下字段的单行结果集:
slot_name (text):新创建的复制插槽的名称。

  • consistent_point (text):插槽变得一致的 WAL 位置。这是可以在此复制插槽上启动流的最早位置。
  • snapshot_name
    (text):命令导出的快照的标识符。在该连接上执行新命令或关闭复制连接之前,快照一直有效。如果创建的插槽是物理插槽,则为 null。
  • output_plugin (text):新创建的复制插槽使用的输出插件的名称。如果创建的插槽是物理插槽,则为 null。

(5)START_REPLICATION

完整命令为:

  1. START_REPLICATION [ SLOT slot_name ] [ PHYSICAL ] XXX/XXX [ TIMELINE
    tli ]

指示服务器从 WAL 的位置 XXX/XX 开始流式传输 WAL。如果指定了 TIMELINE 选项,则流复制从时间线 tli 处开始;否则,将选择服务器的当前时间线。服务器可能会回复一个错误,例如,如果请求的 WAL 部分已经被回收。服务器处理成功后,将使用 CopyBothResponse 消息进行响应,然后开始将 WAL 流式传输到客户端。

如果插槽的名称是通过 slot_name 提供的,则它将随着复制的进行而更新,以便服务器知道备机仍然需要哪些 WAL 段,以及 hot_standby_feedback 是否在事务上依然有效。
如果客户端请求的时间线不是最新的,但是服务器历史的一部分,则服务器将流式传输该时间线上从请求的起始点开始直到服务器切换到另一个时间线为止的所有 WAL。如果客户端在旧时间线的末尾请求流式传输,则服务器将完全跳过 COPY 模式。

在非最新时间线上流式传输所有 WAL 后,服务器将退出 COPY 模式以结束流式传输。当客户端通过退出 COPY 模式来确认这一点时,服务器会发送一个包含一行两列的结果集,指示该服务器历史中的下一个时间线。第一列是下一个时间线的 ID(类型为 int8),第二列是发生切换的 WAL 位置(类型为 text)。

通常,切换位置是流式传输的 WAL 的末尾,但在某些情况下,服务器可以从旧的时间线发送一些 WAL,这些 WAL 是在时间线向前推进之前,服务器本身没有发送的 WAL。最后,服务器发送两条 CommandComplete 消息(一条结束 CopyData,另一条结束 START_REPLICATION 命令本身),并准备接收新命令。

WAL 数据以一系列 CopyData 消息的形式发送。CopyData 消息之间允许混合其他信息。特别是,如果服务器在开始流式传输后遇到故障,则可以发送 ErrorResponse 消息。从服务器到客户端的每个 CopyData 消息的有效负载都包含以下格式之一的消息:

→ XLogData (B)

  • Byte1(‘w’):将消息标识为 WAL 数据。
  • Int64:此消息中 WAL 数据的起点。
  • Int64:服务器上 WAL 的当前结束。
  • Int64:服务器在传输时的系统时钟,自 2000-01-01 午夜起以微秒为单位。
  • Byten:WAL 数据流的部分数据。单个 WAL 记录永远不会拆分为两条 XLogData 消息。当 WAL 记录越过 WAL
    页面边界,因此已经使用连续记录进行拆分时,可以在页面边界进行拆分。也就是说,第一个主 WAL 记录及其后续记录可以在不同的
    XLogData 消息中发送。

→ Primary keepalive message (B)

  • Byte1(‘k’):将消息标识为 sender keepalive。 Int64:服务器上 WAL 的当前结束。

  • Int64:服务器在传输时的系统时钟,自 2000-01-01 午夜起以微秒为单位。

  • Byte1:1,表示客户端应尽快回复此消息,以避免超时断开连接;否则为 0。

客户端接收进程可以随时使用以下消息格式之一(在 CopyData 消息的有效载荷中)将回复发送回 sender:

→ Standby status update (F)

  • Byte1(‘r’):将消息标识为接收方状态更新。 Int64:在备机接收并写入磁盘的最后一个 WAL 字节 + 1 的位置。
  • Int64:在备机刷新到磁盘的最后一个 WAL 字节 + 1 的位置。
  • Int64:在备机应用的最后一个 WAL 字节 + 1 的位置。
  • Int64:传输时客户端的系统时钟,自 2000-01-01 午夜起以微秒为单位。
  • Byte1:1,客户端请求服务器立即回复此消息,可以用来 ping 服务器以测试连接是否仍然正常。

→ Hot Standby feedback message (F)

  • Byte1(‘h’):将消息标识为热备反馈消息。

  • Int64:传输时客户端的系统时钟,自 2000-01-01 午夜起以微秒为单位。

  • Int32:备机的当前全局 xmin,不包括任何复制插槽中的 catalog_xmin。如果 xmin 和下面的 catalog_xmin
    都为 0,则将被视为不再在此连接上发送热备反馈的通知。稍后的非 0 消息可以重新启动反馈机制。

  • Int32:备机的全局 xmin xid 的 epoch。

  • Int32:备机复制插槽中最低的 catalog_xmin。如果备机上不存在 catalog_xmin,或者热备反馈被禁用,则设置为 0。

  • Int32:备机的 catalog_xmin xid 的 epoch。

(6)START_REPLICATION LOGICAL

完整命令为:

  1. START_REPLICATION SLOT slot_name LOGICAL XXX/XXX [ ( option_name [
    option_value ] [, …] ) ]

START_REPLICATION SLOT slot_name LOGICAL XXX/XXX [ ( option_name [ option_value ] [, …] ) ]
指示服务器从 WAL 位置 XXX/XXX 开始流式传输 WAL 以进行逻辑复制。服务器可能会回复一个错误,例如,如果请求的 WAL 部分已经被回收。服务器处理成功后,将使用 CopyBothResponse 消息进行响应,然后开始将 WAL 流式传输到客户端。

CopyBothResponse 消息中的消息与 START_REPLICATION … PHYSICAL 文档中的格式相同,包括两条 CommandComplete 消息。与所选插槽关联的输出插件用于处理流式传输的输出。

  • SLOT slot_name:要变更的流式传输的插槽名称。此参数是必需的,并且必须与在 LOGICAL 模式下使用CREATE_REPLICATION_SLOT 创建的现有逻辑复制插槽相对应。
  • XXX/XXX:开始流式传输的 WAL 位置。 option_name:传递到插槽的逻辑解码插件的选项的名称。
  • option_value:与指定选项关联的字符串常量形式的可选值。

(7)DROP_REPLICATION_SLOT

完整命令为:

  1. DROP_REPLICATION_SLOT slot_name [ WAIT ]

删除复制插槽,释放所有保留的服务器端资源。如果插槽是在 Walsender 连接的数据库之外的数据库中创建的逻辑插槽,则此命令将失败。
slot_name:要删除的插槽的名称。
WAIT:如果插槽处于活动状态,此选项会导致命令等待,直到它变为非活动状态,而不是引发错误的默认行为。

(8)BASE_BACKUP

完整命令为:

  1. BASE_BACKUP [ LABEL ‘label’ ] [ PROGRESS ] [ FAST ] [ WAL ] [ NOWAIT
    ] [ MAX_RATE rate ] [ TABLESPACE_MAP ] [ NOVERIFY_CHECKSUMS ] [
    MANIFEST manifest_option ] [ MANIFEST_CHECKSUMS checksum_algorithm ]

指示服务器开始流式传输基础备份。系统将在备份开始前自动进入备份模式,并在备份完成后退出。BASE_BACKUP 命令接受以下选项:

  • LABEL ‘label’:设置备份的标签。如果未指定,则将使用 base backup 的备份标签。标签的引用规则与打开
    standard_conforming_strings 的标准 SQL 字符串相同。
  • PROGRESS:请求生成进度报告所需的信息。这将在每个表空间的头中发送回一个近似大小,该大小可用于计算流复制的执行进度。这是通过在传输开始之前遍历一次所有文件大小来计算的,因此可能会对性能产生负面影响。特别是,可能需要更长的时间才能开始流式传输第一个数据。由于数据库文件在备份过程中可能会发生变化,因此大小只是近似值,在近似值和发送实际文件大小之间可能会增长和减少。
  • FAST:请求快速检查点。
  • WAL:在备份中包括必要的 WAL 段。这将包括基准目录 tar 文件的 pg_wal 目录中启动和停止备份之间的所有文件。
  • NOWAIT:默认情况下,备份将等待最后一个所需的 WAL 段存档,或者如果未启用日志存档,则会发出警告。指定 NOWAIT
    将禁用等待和警告,让客户端负责确保所需的日志可用。
  • MAX_RATE rate:限制每单位时间从服务器传输到客户端的最大数据量。预期的单位是
    KB/s(千字节每秒)。如果指定了此选项,则该值必须等于零,或者必须在 32 kB 到 1 GB(包括 32 kB 和 1
    GB)的范围内。如果指定选项为 0 或未指定选项,则不会对传输施加任何限制。
  • TABLESPACE_MAP:在名为 tablespace_map 的文件中包含有关目录 pg_tblspc
    中存在的符号链接的信息。表空间映射文件包括目录 pg_tblspc/ 中存在的每个符号链接名称以及该符号链接的完整路径。
  • NOVERIFY_CHECKSUMS:默认情况下,如果启用了校验和,则会在基础备份期间验证校验和。指定
    NOVERIFY_CHECKSUMS 将禁用此验证。
  • MANIFEST manifest_option:如果指定此选项的值为 yes 或
    force-encode,则会创建备份清单并将其与备份一起发送。清单是备份中存在的每个文件的列表,但可能包括的任何 WAL
    文件除外。它还存储每个文件的大小、上次修改时间以及可选的校验和。force-encode
    的值强制所有文件名进行十六进制编码;否则,仅对名称为非 UTF8 八位位组序列的文件执行这种类型的编码。force-encode
    主要用于测试目的,以确保读取备份清单的客户端能够处理这种情况。为了与以前的版本兼容,默认值为 MANIFEST ‘no’。
  • MANIFEST_CHECKSUMS
    checksum_algorithm:指定应用于备份清单中包含的每个文件的校验和算法。目前,可用的算法有
    NONE、CRC32C、SHA224、SHA256、SHA384 和 SHA512。默认值为 CRC32C。

启动备份时,服务器将首先发送两个普通结果集,然后发送一个或多个 CopyOutResponse 结果。

第一个普通结果集为一行两列,包含备份的起始位置。第一列包含以 XLogRecPtr 格式给定的开始位置,第二列包含相应的时间线 ID。

第二个普通结果集为每个表空间有一行。此行中的字段为:

  • spcoid (oid):表空间的 OID,如果是基准目录,则为 null。
  • spclocation (text):表空间目录的完整路径,如果是基准目录,则为 null。
  • size (int8):如果请求了进度报告,则值为表空间的大致大小,以 KB(1024 字节)为单位;否则为 null。

在第二个常规结果集之后,将发送一个或多个 CopyOutResponse 结果,一个用于主数据目录,其他的用于除 pg_default 和 pg_global 之外的每个附加表空间。CopyOutResponse 结果中的数据,除了省略了标准中规定的两个包含 0 值的块之外,是表空间内容的 tar 格式转储(遵循 POSIX 1003.1-2008 标准中指定的“ustar 交换格式”)。

tar 数据完成后,如果请求了备份清单,则会发送另一个 CopyOutResponse 结果,其中包含当前基础备份的清单数据。在任何情况下,都会发送一个最终的普通结果集,其中包含备份的 WAL 结束位置,格式与开始位置相同。

数据目录和每个表空间的 tar 存档将包含目录中的所有文件,无论它们是 PostgreSQL 文件还是添加到同一目录中的其他文件。只排除以下文件:

  • postmaster.pid
  • postmaster.opts
  • pg_internal.init:在多个目录中存在。
  • PostgreSQL 服务器运行过程中创建的各种临时文件和目录,例如以 pgsql_tmp 开头的任何文件或目录以及临时关系表。
  • 未标记的关系表。除了在恢复时重新创建(空的)未标记关系需要的初始化复制文件。
  • pg_wal,包括子目录。如果备份是在包含 WAL 文件的情况下运行的,则会包含 pg_wal
    的合成版本,但它只包含备份工作所需的文件,而不包含其余内容。
  • pg_dynshmem、pg_notify、pg_replslot、pg_serial、pg_snapshots、pg_stat_tmp
    和 pg_subtrans 被复制为空目录(即使它们是符号链接)。
  • 跳过常规文件和目录以外的文件,如符号链接(上面列出的目录除外)和特殊设备文件。pg_tblspc 中的符号链接将得到保留维护。

如果服务器上的底层文件系统支持,则会设置所有者、组和文件模式。