Перейти к основному содержимому

Режимы репликации

примечание

Эта страница переведена при помощи нейросети GigaChat.

Patroni использует потоковую репликацию PostgreSQL. Дополнительную информацию о потоковой репликации смотрите в документации PostgreSQL. По умолчанию Patroni настраивает PostgreSQL на асинхронную репликацию. Выбор схемы репликации зависит от бизнес-соображений. Изучите как асинхронную, так и синхронную репликацию, а также другие HA-решения, чтобы определить, какое решение лучше всего подходит.

Надежность асинхронного режима

В асинхронном режиме кластеру разрешено терять некоторые зафиксированные транзакции для обеспечения доступности. Когда первичный сервер выходит из строя или становится недоступным по любой другой причине, Patroni автоматически повысит достаточно здоровый standby до первичного. Любые транзакции, которые не были реплицированы на этот standby, остаются в «ответвленной временной шкале» на первичном узле и фактически невосстановимы [1].

Количество транзакций, которые могут быть потеряны, контролируется параметром maximum_lag_on_failover. Поскольку позиция журнала транзакций первичного узла не опрашивается в реальном времени, в реальности объем потерянных данных при failover в худшем случае ограничен maximum_lag_on_failover байтами журнала транзакций плюс объем, записанный за последние ttl секунд (в среднем loop_wait/2 секунды). Однако типичная задержка репликации в устойчивом состоянии значительно меньше секунды.

По умолчанию при проведении выборов лидера Patroni не учитывает текущую временную шкалу реплик, что в некоторых случаях может быть нежелательным поведением. Можно предотвратить назначение узла, не имеющего той же временной шкалы, что и бывший первичный узел, новым лидером, изменив значение параметра check_timeline на true.

Синхронная репликация PostgreSQL

Использование синхронной репликации Postgres с Patroni обеспечивает согласованность в кластере, подтверждая, что записи записаны на вторичный узел перед возвратом подключенному клиенту с успехом. Стоимость синхронной репликации: повышенная задержка и сниженная пропускная способность при записи. Эта пропускная способность будет полностью зависеть от производительности сети.

В размещенных средах дата-центров (таких как AWS, Rackspace или любая сеть, которая не контролируется напрямую), синхронная репликация значительно увеличивает вариабельность производительности записи. Если реплики становятся недоступными для лидера, лидер фактически становится доступным только для чтения.

Чтобы включить простой тест синхронной репликации, добавьте следующие строки в раздел parameters файлов конфигурации YAML:

synchronous_commit: "on"
synchronous_standby_names: "*"

При использовании синхронной репликации PostgreSQL используйте как минимум три узла данных Postgres для обеспечения доступности записи при отказе одного хоста.

Использование синхронной репликации PostgreSQL не гарантирует нулевую потерю транзакций при всех обстоятельствах. Когда первичный узел и вторичный узел, который в данный момент действует как синхронная реплика, выходят из строя одновременно, будет повышен третий узел, который может не содержать все транзакции.

Синхронный режим

Для случаев использования, когда потеря зафиксированных транзакций недопустима, можно включить synchronous_mode Patroni. Когда synchronous_mode включен, Patroni не повысит standby, если он не уверен, что standby содержит все транзакции, которые могли вернуть клиенту статус успешного коммита [2]. Это означает, что система может быть недоступна для записи, даже если некоторые серверы доступны. Системные администраторы все еще могут использовать команды ручного failover для повышения standby, даже если это приводит к потере транзакций.

Включение synchronous_mode не гарантирует многоузловую долговечность коммитов при всех обстоятельствах. Когда подходящий standby недоступен, первичный сервер все еще будет принимать записи, но не гарантирует их репликацию. Когда первичный узел выходит из строя в этом режиме, ни один standby не будет повышен. Когда хост, который был первичным, возвращается, он будет автоматически повышен, если только системный администратор не выполнил ручной failover. Такое поведение делает синхронный режим пригодным для использования с кластерами из 2 узлов.

Когда synchronous_mode включен и standby завершается аварийно, коммиты будут блокироваться до следующего запуска итерации Patroni и переключения первичного узла в автономный режим (наихудшая задержка для записей ttl секунд, в среднем loop_wait/2 секунды). Ручное завершение работы или перезапуск standby не вызовет прерывания службы коммитов. Standby подаст сигнал первичному узлу освободить его от обязанностей синхронной реплики перед инициацией завершения работы PostgreSQL.

Когда абсолютно необходимо гарантировать, что каждая запись надежно хранится как минимум на двух узлах, включите synchronous_mode_strict в дополнение к synchronous_mode. Этот параметр предотвращает переключение Patroni на отключение синхронной репликации на первичном узле, когда нет доступных кандидатов в синхронные standby. В качестве недостатка первичный узел не будет доступен для записи (если только транзакция Postgres явно не отключит synchronous_commit), блокируя все клиентские запросы на запись, пока не поднимется как минимум одна синхронная реплика.

Можно гарантировать, что standby никогда не станет синхронной репликой, установив тег nosync в значение true. Рекомендуется устанавливать это для standby, находящихся за медленными сетевыми соединениями, которые вызывали бы деградацию производительности при становлении синхронной репликой. Установка тега nostream в значение true также будет иметь тот же эффект.

Синхронный режим можно включать и выключать с помощью команды patronictl edit-config или через REST-интерфейс Patroni. Инструкции смотрите в разделе Динамическая конфигурация.

Примечание: Из-за того, как синхронная репликация реализована в PostgreSQL, все еще возможно потерять транзакции даже при использовании synchronous_mode_strict. Если бэкенд PostgreSQL отменяется во время ожидания подтверждения репликации (в результате отмены пакета из-за тайм-аута клиента или сбоя бэкенда), изменения транзакции становятся видимыми для других бэкендов. Такие изменения еще не реплицированы и могут быть потеряны в случае повышения standby.

Коэффициент синхронной репликации

Параметр synchronous_node_count используется Patroni для управления количеством синхронных баз данных standby. По умолчанию он установлен в 1. Он не имеет эффекта, когда synchronous_mode установлен в off. Когда включен, Patroni управляет точным количеством синхронных баз данных standby на основе параметра synchronous_node_count и корректирует состояние в DCS и synchronous_standby_names в PostgreSQL при подключении и отключении участников. Если параметр установлен на значение, превышающее количество доступных узлов, он будет автоматически уменьшен Patroni.

Максимальное отставание на синхронном узле

По умолчанию Patroni придерживается узлов, которые объявлены как synchronous согласно представлению pg_stat_replication, даже когда есть другие узлы, опережающие его. Это делается для минимизации количества изменений synchronous_standby_names. Чтобы изменить это поведение, можно использовать параметр maximum_lag_on_syncnode. Он контролирует, насколько большое отставание может иметь реплика, чтобы все еще считаться «синхронной».

Patroni использует максимальный LSN реплики, если есть более одного standby, в противном случае будет использоваться текущий WAL LSN лидера. Значение по умолчанию — -1, и Patroni не будет предпринимать действий для замены нездорового синхронного standby, когда значение установлено в 0 или меньше. Пожалуйста, установите значение достаточно высоким, чтобы Patroni не заменял синхронные standby слишком часто при высокой нагрузке транзакций.

Реализация синхронного режима

В синхронном режиме Patroni поддерживает состояние синхронизации в DCS (ключ /sync), содержащее последний первичный узел и текущие синхронные базы данных standby. Это состояние обновляется с строгими ограничениями порядка для обеспечения следующих инвариантов:

  • Узел должен быть помечен как последний лидер всякий раз, когда он может принимать транзакции записи. Сбой Patroni или незавершение работы PostgreSQL могут вызвать нарушения этого инварианта.
  • Узел должен быть установлен как синхронный standby в PostgreSQL, пока он опубликован как синхронный standby в ключе /sync в DCS.
  • Узел, который не является лидером или текущим синхронным standby, не может автоматически повысить себя.

Patroni будет назначать только один или несколько синхронных узлов standby на основе параметра synchronous_node_count в synchronous_standby_names.

На каждой итерации цикла HA Patroni переоценивает выбор синхронных узлов standby. Если текущий список синхронных узлов standby подключен и не запросил удаление своего синхронного статуса, он остается выбранным. В противном случае выбираются доступные для синхронизации участники кластера, которые наиболее продвинуты в репликации.

Пример

Ключ /config в DCS

synchronous_mode: on
synchronous_node_count: 2
# ...

Ключ /sync в DCS

{
"leader": "node0",
"sync_standby": "node1,node2"
}

postgresql.conf

synchronous_standby_names = 'FIRST 2 (node1,node2)'

В приведенных выше примерах только узлы node1 и node2 известны как синхронные и могут быть автоматически повышены, если первичный узел (node0) выйдет из строя.

Режим коммита на основе кворума

Начиная с PostgreSQL v10 Patroni поддерживает синхронную репликацию на основе кворума.

В этом режиме Patroni поддерживает состояние синхронизации в DCS, содержащее последний известный первичный узел, количество узлов, необходимых для кворума, и узлы, которые в настоящее время имеют право голосовать по кворуму. В устойчивом состоянии узлами, голосующими по кворуму, являются лидер и все синхронные standby. Это состояние обновляется с строгими ограничениями порядка в отношении повышения узлов и synchronous_standby_names, чтобы гарантировать, что в любой момент любое подмножество голосующих, способное достичь кворума, включает как минимум один узел с последним успешным коммитом.

На каждой итерации цикла HA Patroni переоценивает выбор синхронных standby и кворум на основе доступности узлов и запрошенной конфигурации кластера. В версиях PostgreSQL выше 9.6 все доступные узлы добавляются как синхронные standby, как только их репликация догоняет лидера.

Коммит на основе кворума помогает снизить наихудшие задержки даже во время нормальной работы, так как более высокая задержка репликации на один standby может быть компенсирована другими standby.

Синхронный режим на основе кворума можно включить, установив synchronous_mode в quorum с помощью команды patronictl edit-config или через REST-интерфейс Patroni. Инструкции смотрите в разделе Динамическая конфигурация.

Другие параметры, такие как synchronous_node_count, maximum_lag_on_syncnode и synchronous_mode_strict, продолжают работать так же, как и при synchronous_mode=on.

Пример

Ключ /config в DCS

synchronous_mode: quorum
synchronous_node_count: 2
# ...

Ключ /sync в DCS

{
"leader": "node0",
"sync_standby": "node1,node2,node3",
"quorum": 1
}

postgresql.conf

synchronous_standby_names = 'ANY 2 (node1,node2,node3)'

Если первичный узел (node0) вышел из строя, в приведенном выше примере два из node1, node2, node3 будут иметь последнюю полученную транзакцию, но не известно, какие именно. Чтобы выяснить, получил ли узел node1 последнюю транзакцию, необходимо сравнить его LSN с LSN как минимум на одном узле (quorum=1 в ключе /sync) среди node2 и node3. Если node1 не отстает как минимум от одного из них, можно гарантировать, что не будет видимой пользователю потери данных, если node1 будет повышен.

[1] Данные все еще там, но их восстановление требует ручных усилий по восстановлению данных специалистами. Когда Patroni разрешено использовать rewind с use_pg_rewind, ответвленная временная шкала будет автоматически стерта для повторного присоединения отказавшего первичного узла к кластеру. Однако для корректной работы use_pg_rewind кластер должен быть инициализирован с контрольными суммами страниц данных (опция --data-checksums для initdb) и/или wal_log_hints должен быть установлен в on.

[2] Клиенты могут изменять поведение для каждой транзакции с помощью настройки PostgreSQL synchronous_commit. Транзакции со значениями synchronous_commit off и local могут быть потеряны при failover, но не будут блокироваться задержками репликации.