58.5. Протокол логической потоковой репликации #
В этом разделе описывается протокол логической репликации, регламентирующий поток сообщений, который запускается командой репликации START_REPLICATION SLOT имя_слота LOGICAL.
Протокол логической потоковой репликации построен на примитивах протокола физической потоковой репликации.
В логическом декодировании Postgres Pro поддерживаются модули вывода. Стандартный модуль pgoutput используется для встроенной логической репликации.
58.5.1. Параметры протокола логической потоковой репликации #
Используя команду START_REPLICATION, модуль pgoutput принимает следующие параметры:
- proto_version
Версия протокола. В настоящее время поддерживаются только версии
1,2,3и4. Необходимо указывать только рабочую версию.Версия
2, позволяющая передавать в потоке большие выполняющиеся транзакции, поддерживается только с серверами версии 14 и выше.Версия
3, позволяющая передавать фиксацию транзакций в двух фазах, поддерживается только с серверами версии 15 и выше.Версия
4, позволяющая параллельно передавать в потоке большие выполняющиеся транзакции, поддерживается только с серверами версии 16 и выше.- publication_names
Список разделённых запятыми имён публикаций, на которые подписывается клиент (будет получать их изменения). Имена отдельных публикаций обрабатываются как стандартные имена объектов и могут так же заключаться в кавычки при необходимости. Требуется указывать хотя бы одно имя публикации.
- binary
Логический параметр, указывающий использовать режим двоичной передачи. Этот режим работает быстрее текстового, но чуть менее устойчив.
- messages
Логический параметр, который включает отправку сообщений, написанных функцией
pg_logical_emit_message.- streaming
Параметр, позволяющий включить потоковую передачу текущих транзакций. Возможные значения
off(по умолчанию),onиparallel. Значениеparallelвключает отправку дополнительной информации с некоторыми сообщениями, которые будут использоваться для параллельного выполнения. Для включения параметра (on) требуется протокол не ниже версии2. При указании значенияparallelтребуется протокол не ниже версии4.- two_phase
Логический параметр, включающий двухфазные транзакции. Для его включения требуется протокол не ниже версии
3.- origin
Параметр для отправки изменений по их происхождению. Возможные значения:
none, чтобы отправлять только те изменения, для которых не указан источник, илиany, чтобы отправлять изменения независимо от их происхождения. Данный параметр можно использовать, чтобы избежать зацикливаний (бесконечной репликации одних и тех же данных) между узлами репликации.
58.5.2. Сообщения протокола логической репликации #
Отдельные сообщения протокола рассматриваются в следующих подразделах. Собственно сообщения описаны в Раздел 58.9.
Все сообщения верхнего уровня начинаются с байта, определяющего тип сообщения. Хотя он представлен в коде символьным типом, это знаковый байт без явно заданной кодировки.
Так как в протоколе потоковой репликации передаётся длина сообщения, нет необходимости указывать длину в заголовках сообщений верхнего уровня.
58.5.3. Поток сообщений протокола логической репликации #
За исключением команды START_REPLICATION и сообщений о прогрессе воспроизведения, весь информационный поток направлен от сервера к клиенту.
Протокол логической репликации передаёт отдельные транзакции одну за другой. Это значит, что все сообщения между парой сообщений Begin и Commit относятся к одной транзакции. Точно так же к одной транзакции относятся все сообщения между парой сообщений Begin Prepare и Prepare. Этот протокол также передаёт содержимое больших транзакций по ходу их выполнения между парой сообщений Stream Start и Stream Stop. Последний поток для такой транзакции содержит сообщение Stream Commit или Stream Abort.
Каждая передаваемая транзакция содержит ноль или более сообщений DML (Insert, Update, Delete). В каскадной схеме она может также содержать сообщения Origin. Это сообщение показывает, что транзакция пришла с другого узла в схеме репликации. Так как этим узлом в контексте протокола логической репликации может быть что угодно, единственным идентификатором является его имя. Как воспринимать это имя (если это вообще нужно), определяют нижестоящие узлы. Сообщение Origin всегда передаётся перед всеми остальными сообщениями DML в транзакции.
Каждое DML-сообщение содержит идентификатор (OID) отношения, который указывает на целевое отношение на стороне публикации. Перед первым DML-сообщением для данного OID отношения будет отправлено сообщение Relation, описывающее схему данного отношения. Впоследствии будет отправлено новое сообщение Relation, если определение отношения изменится после отправки последнего сообщения Relation. (В протоколе предполагается, что клиент сможет кешировать метаданные для достаточно большого числа отношений.)
В сообщениях Relation типы столбцов определяются идентификаторами (OID). Для встроенного типа предполагается, что клиент может разрешить этот OID локально, поэтому никакие дополнительные данные не нужны. Однако для любых других типов перед сообщением Relation будет передаваться сообщение Type, связывающее имя типа с определённым OID. Таким образом, клиент, которому нужно однозначно определять типы столбцов в отношении, должен кешировать содержимое сообщений Type, и в случае обнаружения полученного OID в кеше использовать эту информацию, а в противном случае разрешать его локально.
58.5. Logical Streaming Replication Protocol #
This section describes the logical replication protocol, which is the message flow started by the START_REPLICATION SLOT slot_name LOGICAL replication command.
The logical streaming replication protocol builds on the primitives of the physical streaming replication protocol.
Postgres Pro logical decoding supports output plugins. pgoutput is the standard one used for the built-in logical replication.
58.5.1. Logical Streaming Replication Parameters #
Using the START_REPLICATION command, pgoutput accepts the following options:
- proto_version
Protocol version. Currently versions
1,2,3, and4are supported. A valid version is required.Version
2is supported only for server version 14 and above, and it allows streaming of large in-progress transactions.Version
3is supported only for server version 15 and above, and it allows streaming of two-phase commits.Version
4is supported only for server version 16 and above, and it allows streams of large in-progress transactions to be applied in parallel.- publication_names
Comma-separated list of publication names for which to subscribe (receive changes). The individual publication names are treated as standard objects names and can be quoted the same as needed. At least one publication name is required.
- binary
Boolean option to use binary transfer mode. Binary mode is faster than the text mode but slightly less robust.
- messages
Boolean option to enable sending the messages that are written by
pg_logical_emit_message.- streaming
Option to enable streaming of in-progress transactions. Valid values are
off(the default),onandparallel. The settingparallelenables sending extra information with some messages to be used for parallelization. Minimum protocol version 2 is required to turn iton. Minimum protocol version 4 is required for theparallelvalue.- two_phase
Boolean option to enable two-phase transactions. Minimum protocol version 3 is required to turn it on.
- origin
Option to send changes by their origin. Possible values are
noneto only send the changes that have no origin associated, oranyto send the changes regardless of their origin. This can be used to avoid loops (infinite replication of the same data) among replication nodes.
58.5.2. Logical Replication Protocol Messages #
The individual protocol messages are discussed in the following subsections. Individual messages are described in Section 58.9.
All top-level protocol messages begin with a message type byte. While represented in code as a character, this is a signed byte with no associated encoding.
Since the streaming replication protocol supplies a message length there is no need for top-level protocol messages to embed a length in their header.
58.5.3. Logical Replication Protocol Message Flow #
With the exception of the START_REPLICATION command and the replay progress messages, all information flows only from the backend to the frontend.
The logical replication protocol sends individual transactions one by one. This means that all messages between a pair of Begin and Commit messages belong to the same transaction. Similarly, all messages between a pair of Begin Prepare and Prepare messages belong to the same transaction. It also sends changes of large in-progress transactions between a pair of Stream Start and Stream Stop messages. The last stream of such a transaction contains a Stream Commit or Stream Abort message.
Every sent transaction contains zero or more DML messages (Insert, Update, Delete). In case of a cascaded setup it can also contain Origin messages. The origin message indicates that the transaction originated on different replication node. Since a replication node in the scope of logical replication protocol can be pretty much anything, the only identifier is the origin name. It's downstream's responsibility to handle this as needed (if needed). The Origin message is always sent before any DML messages in the transaction.
Every DML message contains a relation OID, identifying the publisher's relation that was acted on. Before the first DML message for a given relation OID, a Relation message will be sent, describing the schema of that relation. Subsequently, a new Relation message will be sent if the relation's definition has changed since the last Relation message was sent for it. (The protocol assumes that the client is capable of remembering this metadata for as many relations as needed.)
Relation messages identify column types by their OIDs. In the case of a built-in type, it is assumed that the client can look up that type OID locally, so no additional data is needed. For a non-built-in type OID, a Type message will be sent before the Relation message, to provide the type name associated with that OID. Thus, a client that needs to specifically identify the types of relation columns should cache the contents of Type messages, and first consult that cache to see if the type OID is defined there. If not, look up the type OID locally.