H.2. pg_failover_slots
pg_failover_slots — это расширение Postgres Pro Enterprise, предназначенное для автоматического создания и синхронизации слотов логической репликации на физических репликах.
Поскольку слоты логической репликации доступны только на ведущем узле, до момента создания слота нижестоящие подписчики не получают никаких изменений от узла, недавно ставшего ведущим. Это небезопасно, так как будет утеряна информация о том, получение каких данных подписчик уже подтвердил, а какие данные журнала ещё необходимо сохранить, что приведёт к пробелу в истории изменения данных. Расширение pg_failover_slots позволяет использовать слоты логической репликации при физическом переключении узлов с помощью следующих возможностей:
Копирование всех недостающих слотов репликации с ведущего узла на резервный.
Удаление с резервного узла всех слотов, которые отсутствуют на ведущем.
Периодическая синхронизация позиции слотов на резервном узле с позициями слотов на ведущем узле.
Обеспечение получения данных выбранными резервными узлами до того, как процессы-передатчики WAL логических слотов отправят данные потребителям.
H.2.1. Установка и настройка
Расширение pg_failover_slots поставляется вместе с Postgres Pro Enterprise в виде отдельного пакета pg-failover-slots-ent-14 (подробные инструкции по установке приведены в Главе 17).
После установки Postgres Pro Enterprise выполните следующие действия:
Добавьте расширение pg_failover_slots в shared_preload_libraries на ведущем узле и всех резервных узлах, которые используются для обеспечения высокой доступности (ручного или аварийного переключения узлов):
shared_preload_libraries = 'pg_failover_slots'
Выполните предварительную настройку, как описано в Подразделе H.2.3.
H.2.2. Проверка готовности резервного узла
Чтобы избежать несогласованности, синхронизация слотов происходит не сразу. В момент активации расширения pg_failover_slots резервный узел может сильно отставать или опережать логические слоты на ведущем узле, поэтому расширение проводит проверку и выполняет синхронизацию слотов только тогда, когда это полностью безопасно.
Однако здесь возникает необходимость проверить, что слоты синхронизировались и резервный узел готов стать ведущим, обеспечивая согласованное логическое декодирование для всех слотов. Такую проверку нужно выполнить только в самом начале. Как только слоты синхронизировались в первый раз, они будут оставаться согласованными, пока расширение активно в кластере.
Убедиться, что слоты полностью синхронизировались с ведущим узлом, достаточно просто. Слоты должны присутствовать в представлении pg_replication_slots на резервном узле и иметь состояние active со значением false. Если у состояния active установлено значение true, это значит, что слот находится в процессе инициализации.
Для примера рассмотрим следующий сеанс psql:
# SELECT slot_name, active FROM pg_replication_slots WHERE slot_type = 'logical'; slot_name | active -----------------+-------- regression_slot1 | f regression_slot2 | f regression_slot3 | t
Это означает, что синхронизация слотов regression_slot1 и regression_slot2 между ведущим и резервным узлами завершена, а слот regression_slot3 всё ещё синхронизируется. Если в этот момент произойдёт переключение, слот regression_slot3 будет утерян.
Повторим запрос после небольшого ожидания:
# SELECT slot_name, active FROM pg_replication_slots WHERE slot_type = 'logical'; slot_name | active -----------------+-------- regression_slot1 | f regression_slot2 | f regression_slot3 | f
Теперь все три слота синхронизированы, поэтому можно переключиться на резервный узел без потери состояния логического декодирования ни для одного из них.
H.2.3. Предварительная настройка
Необходимо выполнить следующую настройку, чтобы избежать получения серьёзных ошибок от расширения:
значение параметра hot_standby_feedback должно быть
onзначение параметра primary_slot_name не должно быть пустым
Это необходимо для подключения к ведущему узлу, чтобы обеспечить раздельную отправку xmin и catalog_xmin по hot_standby_feedback.
H.2.4. Параметры конфигурации
Необходимо добавить расширение в shared_preload_libraries как на ведущем узле, так и на всех резервных узлах, которые используются для обеспечения высокой доступности (ручного или аварийного переключения).
Настройку pg_failover_slots можно выполнить с помощью следующих параметров конфигурации (устанавливаемых в postgresql.conf).
pg_failover_slots.synchronize_slot_names(text)Этот параметр резервного узла устанавливает, какой логический слот должен быть синхронизирован на этом физическом резервном узле. Значение передаётся в виде списка фильтров слотов, разделённого запятыми.
Фильтр слотов определяется парой
key:value(ключ и значение, разделённые двоеточием), гдеkeyможет быть представлен одной из нижеприведённых сущностей:nameпроверяет точное соответствие имени слотаname_likeпроверяет соответствие имени слота SQL-выражениюLIKEpluginпроверяет соответствие имени плагина слота указанному значению
Ключ
keyможно не указывать, тогда по умолчанию он будет совпадать с именемname.Например,
'my_slot_name,plugin:test_decoding'будет синхронизировать слот с именемmy_slot_nameи любые слоты, которые используют плагинtest_decoding.Если указать пустую строку, никакие слоты на этом физическом резервном узле не будут синхронизированы.
Значение по умолчанию —
'name_like:%', при котором все слоты логической репликации будут синхронизированы.pg_failover_slots.drop_extra_slots(boolean)Этот параметр резервного узла определяет, как поступить со слотами резервного узла, которые не были обнаружены на ведущем с помощью фильтра pg_failover_slots.synchronize_slot_names. Если задать значение
true(по умолчанию), слоты будут удалены. При значенииfalseслоты будут сохранены.pg_failover_slots.primary_dsn(string)Параметр резервного узла, который указывает строку подключения к ведущему узлу для получения информации о слотах.
Если значение не указано (по умолчанию), используется та же строка подключения, что и в параметре primary_conninfo.
Примечание
Параметр
primary_conninfoнельзя использовать, если в строке подключения задано полеpassword— Postgres Pro скрывает пароль, делая его невидимым для pg_failover_slots. В этом случае необходимо задать значение параметраpg_failover_slots.primary_dsn.pg_failover_slots.standby_slot_names(text)Этот параметр обычно используется в отказоустойчивых конфигурациях для гарантии, что кандидаты на переключение (физические реплики потоковой репликации) получили и записали все изменения до того, как они станут доступны подписчикам. Это гарантирует, что фиксация не исчезнет для потребителя логического слота при переключении на резервный узел.
Слоты репликации, чьи имена перечислены в разделённом запятыми списке
pg_failover_slots.standby_slot_names, особым образом обрабатываются процессами-передатчиками WAL на ведущем узле.Процессы-передатчики WAL, участвующие в логической репликации, обеспечивают отправку и запись всех локальных изменений в слоты репликации, указанные в параметре
pg_failover_slots.standby_slot_names, до того, как процессы-передатчики WAL отправят эти изменения в слоты логической репликации. Фактически это создаёт барьер синхронной репликации между упомянутым списком слотов и всеми потребителями логически декодированных потоков от процессов-передатчиков WAL.Любой слот репликации может быть добавлен в список
pg_failover_slots.standby_slot_names; поддерживаются как логические, так и физические слоты, но в основном используются физические.Без таких мер предосторожности возможна ситуация, при которой подписчик получил фиксацию, но она исчезла на провайдере из-за того, что во время переключения кандидат не получил эту фиксацию. В этом случае могут возникнуть следующие аномалии:
При наличии одного и более подписчиков, подписчик может применить изменение, но дальнейшие транзакции, выполненные на новом провайдере, могут конфликтовать с этим изменением, так как с точки зрения провайдера оно никогда не происходило;
и/или
При наличии двух и более подписчиков, во время переключения возможна ситуация, когда не все подписчики применили изменение. Подписчики в этом случае находятся в несогласованных и противоречащих друг другу состояниях, потому что у тех подписчиков, которые не получили фиксацию, теперь нет возможности её получить.
Настройка параметра
pg_failover_slots.standby_slot_names(как и задумано) приведёт к отставанию подписчиков от провайдера, если реплики-кандидаты на переключение не успевают за ним. Поэтому мониторинг этого процесса крайне важен.pg_failover_slots.standby_slots_min_confirmed(integer)Контролирует, как много слотов репликации из списка pg_failover_slots.standby_slot_names должны прислать подтверждение перед отправкой данных по слотам логической репликации. Значение
-1(по умолчанию) означает, что будет ожидаться подтверждение от всех указанных вpg_failover_slots.standby_slot_namesслотов.pg_failover_slots.worker_nap_time(integer)Время ожидания (в миллисекундах) между двумя попытками синхронизации. Значение по умолчанию — 60s.
pg_failover_slots.maintenance_db(text)Имя базы данных, которая будет использоваться в primary_conninfo для подключения к ведущему серверу и получения списка слотов репликации. Значение по умолчанию —
postgres.
H.2. pg_failover_slots
pg_failover_slots is a Postgres Pro Enterprise extension designed for automatic creation and synchronization of logical replication slots on physical replicas.
Since logical replication slots are only maintained on the primary node, downstream subscribers don’t receive any new changes from a newly promoted primary until the slot is created. This is unsafe because the information that includes which data a subscriber has confirmed receiving and which log data still needs to be retained for the subscriber will have been lost, resulting in an unknown gap in data changes. The pg_failover_slots extension makes logical replication slots usable across a physical failover using the following features:
Copies any missing replication slots from the primary to the standby.
Removes any slots from the standby that aren’t found on the primary.
Periodically synchronizes the position of slots on the standby based on the primary.
Ensures that selected standbys receive data before any of the logical slot walsenders can send data to consumers.
H.2.1. Installation and Configuration
The pg_failover_slots extension is provided with Postgres Pro Enterprise as a separate pre-built package pg-failover-slots-ent-14 (for the detailed installation instructions, see Chapter 17).
Once you have Postgres Pro Enterprise installed, do the following:
Add the pg_failover_slots extension to shared_preload_libraries on both the primary instance and any standby that is used for high availability (failover or switchover) purposes:
shared_preload_libraries = 'pg_failover_slots'
Configure prerequisite settings as described in Section H.2.3.
H.2.2. How to Check the Standby Is Ready
The slots are not synchronized to the standby immediately because of consistency reasons. The standby can be too behind logical slots, or too ahead of logical slots on primary when the pg_failover_slots module is activated, so the module does verification and only synchronizes slots when it’s actually safe.
This, however, brings a need to verify that the slots are synchronized and that the standby is actually ready to be a failover target with consistent logical decoding for all slots. This only needs to be done initially. Once the slots are synchronized for the first time, they will always be consistent as long as the module is active in the cluster.
The check for whether slots are fully synchronized with primary is relatively simple. The slots just need to be present in the pg_replication_slots view on standby and have the active state set to false. The active state set to true means the slots is currently being initialized.
For example, consider the following psql session:
# SELECT slot_name, active FROM pg_replication_slots WHERE slot_type = 'logical'; slot_name | active -----------------+-------- regression_slot1 | f regression_slot2 | f regression_slot3 | t
This means that slots regression_slot1 and regression_slot2 are synchronized from primary to standby and regression_slot3 is still being synchronized. If failover happens at this stage, the regression_slot3 will be lost.
Now let’s wait a little and query again:
# SELECT slot_name, active FROM pg_replication_slots WHERE slot_type = 'logical'; slot_name | active -----------------+-------- regression_slot1 | f regression_slot2 | f regression_slot3 | f
Now all three slots are synchronized and the standby can be used for failover without losing logical decoding state for any of them.
H.2.3. Prerequisite Settings
The module throws hard errors if the following settings are not adjusted:
hot_standby_feedback should be
onprimary_slot_name should be non-empty
These are necessary to connect to the primary so it can send the xmin and catalog_xmin separately over hot_standby_feedback.
H.2.4. Configuration Options
The module itself must be added to shared_preload_libraries on both the primary instance as well as any standby that is used for high availability (failover or switchover) purposes.
The behavior of pg_failover_slots is configurable using these configuration options (set in postgresql.conf).
pg_failover_slots.synchronize_slot_names(text)This standby option allows setting which logical slots should be synchronized to this physical standby. It’s a comma-separated list of slot filters.
A slot filter is defined as
key:valuepair (separated by colon) wherekeycan be one of:namespecifies to match exact slot namename_likespecifies to match slot name against SQLLIKEexpressionpluginspecifies to match slot plugin name against the value
The
keycan be omitted and will default tonamein that case.For example,
'my_slot_name,plugin:test_decoding'will synchronize the slot namedmy_slot_nameand any slots that use thetest_decodingplugin.If this is set to an empty string, no slots will be synchronized to this physical standby.
The default value is
'name_like:%', which means all logical replication slots will be synchronized.pg_failover_slots.drop_extra_slots(boolean)This standby option controls what happens to extra slots on the standby that are not found on the primary using the pg_failover_slots.synchronize_slot_names filter. If it’s set to
true(which is the default), they will be dropped, otherwise they will be kept.pg_failover_slots.primary_dsn(string)A standby option for specifying the connection string to use to connect to the primary when fetching slot information.
If empty (default), then the same connection string as primary_conninfo is used.
Note
The
primary_conninfoparameter cannot be used if there is apasswordfield in the connection string because it gets obfuscated by Postgres Pro and pg_failover_slots can’t actually see the password. In this case,pg_failover_slots.primary_dsnmust be configured.pg_failover_slots.standby_slot_names(text)This option is typically used in failover configurations to ensure that the failover-candidate streaming physical replica(s) have received and flushed all changes before they ever become visible to any subscribers. That guarantees that a commit cannot vanish on failover to a standby for the consumer of a logical slot.
Replication slots which names are listed in the comma-separated
pg_failover_slots.standby_slot_nameslist are treated specially by the walsender on the primary.Logical replication walsenders will ensure that all local changes are sent and flushed to the replication slots in
pg_failover_slots.standby_slot_namesbefore the walsender sends those changes for the logical replication slots. Effectively, it provides a synchronous replication barrier between the named list of slots and all the consumers of logically decoded streams from the walsender.Any replication slot may be listed in
pg_failover_slots.standby_slot_names; both logical and physical slots work, but it’s generally used for physical slots.Without this safeguard, two anomalies are possible where a commit can be received by a subscriber and then vanish from the provider on failover because the failover candidate hadn’t received it yet:
For 1+ subscribers, the subscriber may have applied the change but the new provider may execute new transactions that conflict with the received change, as it never happened as far as the provider is concerned;
and/or
For 2+ subscribers, at the time of failover, not all subscribers have applied the change. The subscribers now have inconsistent and irreconcilable states because the subscribers that didn’t receive the commit have no way to get it now.
Setting
pg_failover_slots.standby_slot_nameswill (by design) cause subscribers to lag behind the provider if the provider’s failover-candidate replica(s) are not keeping up. Monitoring is thus essential.pg_failover_slots.standby_slots_min_confirmed(integer)Controls how many of the pg_failover_slots.standby_slot_names have to confirm before sending data through the logical replication slots. Setting
-1(the default) means to wait for all entries inpg_failover_slots.standby_slot_names.pg_failover_slots.worker_nap_time(integer)Time to sleep (in ms) between two synchronization attempts. Defaults to 60s.
pg_failover_slots.maintenance_db(text)Database name to use when using primary_conninfo to connect to the primary server and fetch the replication slots list. Defaults to
postgres.