Режимы репликации
Patroni использует потоковую репликацию PostgreSQL. Подробнее о потоковой репликации см. документацию Postgres . По умолчанию Patroni настраивает PostgreSQL на асинхронную репликацию. Выбор схемы репликации зависит от требований бизнеса. Изучите асинхронную и синхронную репликацию, а также другие решения HA, чтобы выбрать подходящий вариант.
Долговечность в асинхронном режиме
В асинхронном режиме ради доступности кластер может потерять часть зафиксированных транзакций. При отказе или недоступности первичного сервера Patroni автоматически повышает достаточно исправный резервный сервер до первичного. Транзакции, не реплицированные на этот резервный сервер, остаются в «ответвившейся временной шкале» первичного и фактически невосстановимы1.
Объём транзакций, которые могут быть потеряны, контролируется параметром maximum_lag_on_failover. Поскольку позиция журнала транзакций первичного сервера не измеряется в реальном времени, в худшем случае при переключении теряется maximum_lag_on_failover байтов журнала плюс объём, записанный за последние ttl секунд (в среднем за loop_wait/2 секунд). Однако типичная задержка репликации в стабильном состоянии значительно меньше секунды.
По умолчанию при выборах лидера Patroni не учитывает текущую временную шкалу реплик, что иногда нежелательно. Задайте check_timeline значение true, чтобы узел с временной шкалой, более ранней, чем последняя известная шкала кластера, либо с неопределимой шкалой не мог стать новым лидером.
Синхронная репликация PostgreSQL
С Patroni можно использовать синхронную репликацию Postgres. Она обеспечивает согласованность кластера, подтверждая запись на вторичный сервер до возврата успешного результата подключённому клиенту. Цена синхронной репликации — повышенная задержка и сниженная пропускная способность записи, на которую влияет производительность сети.
В размещённых окружениях центров обработки данных, например AWS, Rackspace или любой неподконтрольной сети, синхронная репликация значительно повышает изменчивость производительности записи. Если последователи становятся недоступны лидеру, лидер фактически переходит в режим только для чтения.
Для простого теста синхронной репликации добавьте следующие строки в раздел parameters файлов конфигурации YAML:
При синхронной репликации PostgreSQL используйте не менее трёх узлов данных Postgres, чтобы сохранить доступность записи при отказе одного узла.
Синхронная репликация PostgreSQL не гарантирует отсутствие потерь транзакций при любых обстоятельствах. Если первичный и вторичный сервер, служащий синхронной репликой, отказывают одновременно, будет повышен третий узел, который может содержать не все транзакции.
Синхронный режим
Для сценариев, где потеря зафиксированных транзакций недопустима, включите synchronous_mode Patroni. При включённом synchronous_mode Patroni не повышает резервный сервер, пока не убедится, что тот содержит все транзакции, для которых клиент мог получить успешный статус фиксации2. Поэтому система может быть недоступна для записи, хотя часть серверов работает. Системные администраторы всё ещё могут вручную переключить резервный сервер при отказе, даже если это приведёт к потере транзакций.
Включение synchronous_mode не гарантирует долговечность фиксаций на нескольких узлах при любых обстоятельствах. Если подходящего резервного сервера нет, первичный всё равно принимает записи, но не гарантирует их репликацию. При отказе первичного сервера в этом режиме резервный сервер не повышается. Когда прежний первичный узел возвращается, он повышается автоматически, если системный администратор не выполнил ручное переключение. Благодаря этому синхронный режим применим в кластерах из 2 узлов.
Если synchronous_mode
включён, строгий режим отключён и единственный синхронный резервный сервер отказывает, фиксации блокируются до следующей итерации Patroni, которая переводит первичный сервер в автономный режим (задержка записи в худшем случае — ttl секунд, в среднем — loop_wait/2 секунд). Ручная остановка или перезапуск резервного сервера не прерывает службу фиксации: до остановки PostgreSQL резервный сервер сообщает первичному, что освобождается от обязанностей синхронной реплики.
Если абсолютно необходимо гарантировать долговечное хранение каждой записи как минимум на двух узлах, в дополнение к synchronous_mode
включите synchronous_mode_strict. Этот параметр не позволяет Patroni отключать синхронную репликацию на первичном сервере при отсутствии подходящих резервных кандидатов. Синхронные фиксации блокируются до появления синхронной реплики; транзакции со значениями synchronous_commit off или local обходят это ожидание.
В синхронном режиме на основе приоритетов (synchronous_mode: on), если строгий режим включён и подходящего синхронного резервного сервера нет, Patroni 4.1.5 задаёт synchronous_standby_names равным * и выдаёт предупреждение "No standbys available!". Фиксации продолжают ждать синхронного резервного сервера. Этот шаблон не ограничивает подтверждения именами участников, ранее записанными в /sync.
Если тег nosync равен true, Patroni исключает резервный сервер из своего выбора синхронных резервных серверов. Это рекомендуется для резервных серверов за медленными сетевыми соединениями, которые снизили бы производительность в роли синхронной реплики. Тег nostream, равный true, даёт тот же эффект.
Синхронный режим можно включать и отключать командой patronictl edit-config или через REST-интерфейс Patroni. Инструкции приведены в разделе динамической конфигурации
.
Примечание: из-за реализации синхронной репликации в PostgreSQL транзакции можно потерять даже с synchronous_mode_strict. Если бэкенд PostgreSQL отменён в ожидании подтверждения репликации, например из-за запроса отмены после тайм-аута клиента или отказа бэкенда, изменения транзакции становятся видимыми другим бэкендам. Они ещё не реплицированы и могут быть потеряны при повышении резервного сервера.
Коэффициент синхронной репликации
Параметр synchronous_node_count управляет количеством синхронных резервных баз данных в Patroni. По умолчанию он равен 1 и не действует, если synchronous_mode
равен off. При включении Patroni поддерживает точное количество синхронных резервных баз по synchronous_node_count и корректирует состояние в DCS и synchronous_standby_names PostgreSQL при присоединении и выходе участников. При недостаточном количестве подходящих узлов Patroni может использовать меньше синхронных резервных серверов, чем запрошено; однако в строгом режиме кворума фиксации по-прежнему ждут настроенное количество подтверждений от резервных серверов.
Максимальное отставание синхронного узла
По умолчанию Patroni сохраняет узлы, объявленные synchronous согласно представлению pg_stat_replication, даже если другие узлы опережают их. Это уменьшает количество изменений synchronous_standby_names. Поведение можно изменить параметром maximum_lag_on_syncnode, который определяет допустимое отставание реплики, всё ещё считающейся «синхронной».
Если резервных серверов несколько, Patroni использует максимальный LSN реплики, иначе — текущий LSN WAL лидера. По умолчанию значение равно -1; при значении 0 или меньше Patroni не заменяет неисправный синхронный резервный сервер. Задайте достаточно высокое значение, чтобы Patroni не менял синхронные реплики слишком часто при большом объёме транзакций.
Реализация синхронного режима
В синхронном режиме Patroni поддерживает в DCS состояние синхронизации (ключ /sync), содержащее сведения о последнем первичном сервере и текущих синхронных резервных базах. Состояние обновляется со строгими ограничениями порядка, обеспечивая следующие инварианты:
- Узел должен быть отмечен как последний лидер всякий раз, когда он может принимать транзакции записи. Отказ Patroni или незавершённая остановка PostgreSQL могут нарушить этот инвариант.
- Узел должен быть задан синхронным резервным сервером PostgreSQL, пока он опубликован как синхронный резервный сервер в ключе
/syncDCS. - Узел, не являющийся лидером или текущим синхронным резервным сервером, не может автоматически повысить себя.
Если набор синхронных резервных серверов не пуст, Patroni назначает в synchronous_standby_names один или несколько таких узлов с учётом synchronous_node_count.
На каждой итерации цикла HA Patroni заново оценивает выбор синхронных резервных узлов. Если узлы текущего списка подключены и не запросили снятие синхронного статуса, список сохраняется. Иначе выбираются доступные для синхронизации участники кластера, сильнее всего продвинувшиеся в репликации.
Пример:
Ключ /config в DCS
Ключ /sync в DCS
postgresql.conf
В приведённых примерах только узлы node1 и node2 считаются синхронными и могут быть автоматически повышены при отказе первичного сервера (node0).
Режим фиксации по кворуму
Начиная с PostgreSQL v10 Patroni поддерживает синхронную репликацию на основе кворума.
В этом режиме Patroni поддерживает в DCS состояние синхронизации, содержащее сведения о последнем известном первичном сервере, количестве узлов, необходимых для кворума, и об узлах, которые в настоящее время имеют право голосовать по кворуму. В стабильном состоянии голосующие узлы — лидер и все синхронные резервные серверы. Состояние обновляется со строгими ограничениями порядка повышения узлов и synchronous_standby_names, чтобы любое способное достичь кворума подмножество голосующих всегда содержало хотя бы один узел с последней успешной фиксацией.
На каждой итерации цикла HA Patroni заново оценивает выбор синхронных резервных серверов и кворум по доступности узлов и запрошенной конфигурации кластера. В версиях PostgreSQL выше 9.6 все подходящие узлы добавляются как синхронные резервные серверы, как только их репликация догоняет лидера.
Фиксация по кворуму снижает задержку в худшем случае даже при нормальной работе, поскольку высокая задержка репликации на один резервный сервер компенсируется другими.
Синхронный режим на основе кворума включается установкой synchronous_mode
в quorum командой patronictl edit-config или через REST-интерфейс Patroni. Инструкции приведены в разделе динамической конфигурации
.
Остальные параметры, включая synchronous_node_count, maximum_lag_on_syncnode и synchronous_mode_strict, работают так же, как при synchronous_mode=on.
В режиме фиксации по кворуму, когда набор синхронных резервных серверов пуст и строгий режим требует N подтверждений от резервных серверов, Patroni 4.1.5 задаёт synchronous_standby_names равным ANY N (*).
Пример:
Ключ /config в DCS
Ключ /sync в DCS
postgresql.conf
При отказе первичного сервера (node0) в приведённом примере два узла из node1, node2, node3 получат последнюю транзакцию, но неизвестно какие. Чтобы определить, получил ли её node1, нужно сравнить его LSN с LSN как минимум одного узла (quorum=1 в ключе /sync) из node2 и node3. Если node1 не отстаёт хотя бы от одного из них, можно гарантировать отсутствие видимой пользователю потери данных при повышении node1.
-
Данные всё ещё существуют, но для их извлечения требуется ручная работа специалистов по восстановлению. Если Patroni разрешено перематывать состояние с
use_pg_rewind, ответвившаяся временная шкала автоматически удаляется, чтобы снова присоединить отказавший первичный сервер к кластеру. Для правильной работыuse_pg_rewindкластер должен быть инициализирован сdata page checksums(параметр--data-checksumsдляinitdb) и/илиwal_log_hintsдолжен быть равенon. ↩︎ -
Клиенты могут изменять поведение отдельных транзакций параметром PostgreSQL
synchronous_commit. Транзакции со значениямиsynchronous_commitoffиlocalмогут быть потеряны при переключении, но не блокируются задержкой репликации. ↩︎