01 流复制介绍
PostgreSQL 支持 COPY 操作,COPY 操作通过流复制协议(Streaming Replication Protocol)实现。COPY 命令允许在服务器之间进行高速批量数据传输,有三种流复制模式:
- COPY-IN 模式
数据从客户端传输到服务器端。
- COPY-OUT 模式
数据从服务器端传输到客户端。
- COPY-BOTH 模式
服务器端和客户端数据可以双向传输。
COPY-IN 和 COPY-OUT 操作分别将连接切换到一个不同于正常命令处理的子协议中,该子协议一直持续到操作完成;不同于 COPY-IN 和 COPY-OUT 模式,COPY-BOTH 模式是从狭义上定义的流复制协议,我们将上述统一称为流复制协议。
- COPY-IN 模式
当服务器端收到并执行 COPY FROM STDIN SQL 语句时,将启动 COPY-IN 模式(从客户端向服务器传输数据)。服务器端向客户端发送 CopyInResponse 消息。然后,客户端应该发送 0 个或多个 CopyData 消息,形成一个输入数据流。
消息边界与行边界保持一致看似是一个合理的选择,但实际上它们没有任何关系,也不是必需的。客户端可以通过发送 CopyDone 消息(允许成功终止)或 CopyFail 消息(将导致 COPY SQL 语句执行失败并返回错误)来终止 COPY-IN 模式。然后,服务器端将恢复到 COPY 启动前的正常命令处理模式——简单查询协议或扩展查询协议流程。服务器端接下来将发送 CommandComplete(如果执行成功)或 ErrorResponse(如果执行失败)。
如果在执行 COPY-IN 模式期间服务器端检测到错误(包括收到 CopyFail 消息),将发出 ErrorResponse 消息。如果 COPY 命令是通过扩展查询消息发出的,则服务器端将立即丢弃客户端消息,直到收到 Sync 消息,然后服务器端将发出 ReadyForQuery 消息并返回正常处理。如果 COPY 命令是在简单查询的 Query 消息中发出的,则该消息的其余部分将被丢弃,服务器端发出 ReadyForQuery 消息。在前述任何一种情况下,客户端发出的任何后续 CopyData、CopyDone 或 CopyFail 消息都将被丢弃。
服务器端在 COPY-IN 模式中将忽略接收到的 Flush 和 Sync 消息。服务器端接收到任何其他非复制消息类型都会被算作一个错误,该错误将中止上述的 COPY-IN 状态。需要注意的是,Flush 和 Sync 作为例外情况是为了方便客户端库,客户端总是在 Execute 消息后发送 Flush 或 Sync,而不检查要执行的命令是否为 COPY FROM STDIN。
- COPY-OUT 模式
当服务器端接收并执行 COPY TO STDOUT SQL 语句时,将启动 COPY-OUT 模式(从服务器向外传输数据)。服务器端向客户端端发送一条 CopyOutResponse 消息,然后是 0 条或多条 CopyData 消息(总是每行一条),后跟 CopyDone 消息。然后,服务器端恢复到 COPY 启动前的命令处理模式,并发送 CommandComplete。
客户端无法中止传输(除非关闭连接或发出 Cancel 请求),但它可以丢弃不需要的 CopyData 和 CopyDone 消息。如果服务器端在 COPY-OUT 模式期间检测到错误,将发出 ErrorResponse 消息并恢复到正常处理模式。客户端应将收到 ErrorResponse 视为终止 COPY-OUT 模式。
NoticeResponse 和 ParameterStatus 消息可以散布在 CopyData 消息之间;客户端必须处理这些情况,并应为其他异步消息类型做好准备。除此之外,除 CopyData 或 CopyDone 之外的任何消息类型都可能被视为终止 COPY-OUT 模式。
- COPY-BOTH 模式
COPY-BOTH 是一种与 COPY 相关的模式,它允许在服务器之间或服务器与客户端之间进行高速批量数据传输。当处于 Walsender 模式中的服务器端执行 START_REPLICATION 语句时,将启动 COPY-BOTH 模式。服务器端向客户端发送 CopyBothResponse 消息。然后,服务器端和客户端都可以发送 CopyData 消息,直到任意一端发送 CopyDone 消息。
客户端发送 CopyDone 消息后,连接将从 COPY-BOTH 模式切换到 COPY-OUT 模式,并且客户端不可以再发送任何 CopyData 消息。类似地,当服务器发送 CopyDone 消息时,连接将切换到 COPY-IN 模式,并且服务器不可以再发送任何 CopyData 消息。当服务器端和客户端双方都发送了 CopyDone 消息后,COPY 模式将终止,服务器端将恢复到正常的命令处理模式。
如果服务器端在 COPY-BOTH 模式期间检测到错误,将发出 ErrorResponse 消息,丢弃客户端消息,直到收到 Sync 消息,然后发出 ReadyForQuery 消息并返回正常处理模式。客户端应将收到 ErrorResponse 视为终止双向复制;在这种情况下,不应发送 CopyDone 消息。
CopyInResponse、CopyOutResponse 和 CopyBothResponse 消息包含向客户端通知每行的列数以及每列使用的格式代码的字段。在目前的实现中,给定 COPY 操作中的所有列都将使用相同的格式,但消息格式的设计并不做这样的假设。
02 复制命令
当需要启动流复制时,客户端端会在 StartupMessage 消息中发送 replication 参数。replication 参数的布尔值 true(或 on,yes,1)告诉服务器端进入物理复制 Walsender 模式,其中可以发出如一小组复制命令,而不是 SQL 语句。
如果 replication 参数的值设置为 replication=database,会指示服务器端进入逻辑复制 Walsender 模式,连接到 dbname 参数中指定的数据库。在逻辑复制 Walsender 模式中,可以发出复制命令以及普通的 SQL 命令。在物理复制或逻辑复制 Walsender 模式中,只能使用简单的查询协议。
为了测试复制命令,可以使用带有包括 replication 选项的连接字符串的工具,通过 psql 或任何其他 libpq 驱动建立复制连接。例如,建立逻辑复制连接:
- Shell
- psql “dbname=postgres replication=database” -c “IDENTIFY_SYSTEM;”
但是,使用 pg_receivewal(用于物理复制)或 pg_recvlogic(用于逻辑复制)工具通常更有用。如果连接中 log_replication_commands 启用时,复制命令会记录在服务器日志中。
在复制模式下可以接受的命令包括以下 8 种