F.30. multimaster

Содержание

Ограничения

Архитектура

Установка и подготовка

Администрирование кластера multimaster

Справка

Совместимость

Авторы

multimaster — это расширение Postgres Pro Enterprise, которое в сочетании с набором доработок ядра превращает Postgres Pro Enterprise в синхронный кластер без разделения ресурсов, который обеспечивает расширяемость OLTP для читающих транзакций, а также высокую степень доступности с автоматическим восстановлением после сбоев.

По сравнению со стандартным кластером PostgreSQL конструкции ведущий-ведомый, в кластере, построенном с использованием multimaster, все узлы являются ведущими. Это даёт следующие преимущества:

Расширение multimaster реплицирует вашу базу данных на все узлы кластера и разрешает выполнять пишущие транзакции на любом узле. Для согласованности данных в случае одновременных изменений multimaster обеспечивает изоляцию транзакций в рамках всего кластера, реализуя MVCC (Multiversion Concurrency Control, Многоверсионное управление конкурентным доступом) на уровнях изоляции Read Committed и Repeatable Read. Каждая пишущая транзакция синхронно реплицируется на все узлы, что увеличивает задержку фиксации на время, требующееся для синхронизации. Читающие транзакции и запросы выполняются локально, без каких-либо ощутимых издержек.

Для обеспечения высокой степени доступности и отказоустойчивости кластера multimaster использует протокол трёхфазной фиксации и контроль состояния для обнаружения сбоев. Кластер с N ведущими узлами может продолжать работать, пока функционируют и доступны друг для друга большинство узлов. Чтобы в кластере можно было настроить multimaster, он должен включать в себя как минимум два узла. Чаще всего для обеспечения высокой степени доступности достаточно трёх узлов. Так как на всех узлах кластера будут одни и те же данные, обычно нет смысла делать более пяти узлов в кластере.

Когда узел снова подключается к кластеру, multimaster может автоматически привести его в актуальное состояние и наверстать упущенное, используя данные WAL из соответствующего слота репликации. Если данные WAL на момент времени, когда узел был исключён из кластера, оказываются недоступны, этот узел можно восстановить, воспользовавшись pg_basebackup.

Важно

Применяя multimaster, необходимо учитывать ограничения, связанные с репликацией. За подробностями обратитесь к Подразделу F.30.1.

Чтобы узнать больше о внутреннем устройстве multimaster, обратитесь к Подразделу F.30.2.

F.30.1. Ограничения

Расширение multimaster осуществляет репликацию данных полностью автоматическим образом. Вы можете одновременно выполнять пишущие транзакции и работать с временными таблицами на любом узле кластера. Однако, при этом нужно учитывать следующие ограничения репликации:

  • multimaster может реплицировать только одну базу данных в кластере, заданную в переменной multimaster.conn_strings. Если вы попытаетесь подключиться к другой базе данных, multimaster выдаст соответствующее сообщение об ошибке.

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

    Примечание

    Вы можете включить репликацию таблиц без первичных ключей, присвоив переменной multimaster.ignore_tables_without_pk значение false. Однако учтите, что multimaster не поддерживает операции изменения в таких таблицах.

  • Уровень изоляции. Расширение multimaster поддерживает только уровни изоляции read committed и repeatable read. Уровень Serializable в настоящее время не поддерживается.

    Важно

    На уровне repeatable read более вероятны сбои сериализации в момент фиксации. В отличие от стандартного PostgreSQL, в кластере multimaster на уровне read committed также могут происходить сбои сериализации.

    Когда выполняется пишущая транзакция, multimaster блокирует задействуемые объекты только на том узле, где она выполняется. Но так как пишущие транзакции могут выполняться на всех узлах, другие транзакции могут попытаться в то же время изменить те же объекты, что и соседние узлы. В этом случае репликация первой транзакции будет невозможна, так как задействованные объекты уже будут заблокированы другой транзакцией. По той же причине и последующую транзакцию нельзя будет реплицировать на первый узел. В этом случае происходит распределённая взаимоблокировка. В результате одна из транзакций автоматически откатывается и её необходимо повторить. Приложение в такой ситуации должно быть готово повторять транзакции.

    Если у вас при типичной нагрузке происходит слишком много откатов транзакций, рекомендуется использовать уровень изоляции read committed. Однако уровень read committed всё же не гарантирует отсутствие взаимоблокировок в кластере multimaster. Если использование уровня read committed не помогает, попробуйте направить все пишущие транзакции на один узел.

  • Генерация последовательностей. Во избежание конфликтов уникальных идентификаторов на разных узлах, multimaster меняет стандартное поведение генераторов последовательностей. Для каждого узла идентификаторы генерируются, начиная с номера узла, и увеличиваются на число узлов. Например, в кластере с тремя узлами, идентификаторы 1, 4 и 7 выделяются для объектов, создаваемых на первом узле, а 2, 5 и 8 резервируются для второго узла. Если число узлов в кластере изменяется, величина прироста идентификаторов корректируется соответственно. Таким образом, значения последовательностей будут не монотонными.

  • Репликация DDL. Тогда как multimaster реплицирует данные на логическом уровне, DDL реплицируется на уровне операторов, что приводит к распределённой фиксации одного и того же оператора на разных узлах. В результате сложные сценарии с DDL, например хранимые процедуры и временные таблицы, могут работать не так, как в стандартном PostgreSQL.

  • Задержка фиксации. В текущей реализации логической репликации multimaster передаёт данные узлам-подписчикам только после локальной фиксации, так что приходится ожидать двойной обработки транзакции: сначала на локальном узле, а затем на всех других узлах одновременно. Если транзакция производит запись в большом объёме, задержка может быть весьма ощутимой.

Если какие-либо данные должны присутствовать только на одном из узлов кластера, вы можете исключить таблицу с ними из репликации следующим образом:

SELECT * FROM mtm.make_table_local('имя_таблицы') 

F.30.2. Архитектура

F.30.2.1. Репликация

Так как каждый сервер в кластере multimaster может принимать запросы на запись, любой сервер может прервать транзакцию из-за параллельного изменения — так же как это происходит на одном сервере с несколькими обслуживающими процессами. Чтобы обеспечить высокую степень доступности и согласованность данных на всех узлах кластера, multimaster применяет логическую репликацию и протокол трёхфазной фиксации E3PC.

Когда Postgres Pro Enterprise загружает разделяемую библиотеку multimaster, код multimaster создаёт поставщика и потребителя логической репликации для каждого узла и внедряется в процедуру фиксирования транзакций. Типичная последовательность действий при репликации данных включает следующие фазы:

  1. Фаза PREPARE. Код multimaster перехватывает каждый оператор COMMIT и преобразует его в оператор PREPARE. Все узлы, получающие транзакцию через протокол репликации (узлы когорты), передают свой голос для одобрения или отклонения транзакции процессу-арбитру на исходном узле. Это гарантирует, что вся когорта может принять эту транзакцию и конфликт при записи отсутствует. Подробнее поддержка транзакций с PREPARE в PostgreSQL рассматривается в описании PREPARE TRANSACTION.

  2. Фаза PRECOMMIT. Если все узлы когорты одобряют транзакцию, процесс-арбитр отправляет всем этим узлам сообщение PRECOMMIT, выражающее намерение зафиксировать эту транзакцию. Узлы когорты отвечают арбитру сообщением PRECOMMITTED. В случае сбоя все узлы могут использовать эту информацию для завершения транзакции по правилам кворума.

  3. Фаза COMMIT. Если результат PRECOMMIT положительный, арбитр фиксирует транзакцию на всех узлах.

Важно

Расширение multimaster в настоящее время поддерживает только уровни изоляции read committed и repeatable read, с которыми в рабочей нагрузке могут происходить сбои сериализации. За подробностями обратитесь к Подразделу F.30.1.

Если узел отказывает или отключается от кластера между фазами PREPARE и COMMIT, фаза PRECOMMIT даёт гарантию, что оставшиеся в строю узлы имеют достаточно информации для завершения подготовленной транзакции. Сообщения PRECOMMITTED помогают избежать ситуации, когда отказавший узел мог бы зафиксировать или прервать транзакцию, но не успел бы уведомить о состоянии транзакции другие узлы. При двухфазной фиксации (2PC, two-phase commit), такая транзакция заблокировала бы ресурсы (удерживала блокировки) до восстановления отказавшего узла. В противном случае была бы возможна несогласованность данных после восстановления отказавшего узла, например, если отказавший узел зафиксировал транзакцию, а оставшийся узел откатил её.

Для фиксирования транзакции арбитр должен получить ответ от большинства узлов. Например, в кластере из 2N + 1 узлов необходимо получить минимум N+1 ответов. Таким образом multimaster обеспечивает доступность кластера для чтения и записи пока работает большинство узлов и гарантирует согласованность данных при отказе узла или прерывании соединения. Подробнее механизм обнаружения сбоев описан в Подразделе F.30.2.2.

F.30.2.2. Обнаружение сбоя и восстановление

Так как multimaster допускает запись на всех узлах, он должен ждать ответа с подтверждением транзакции от всех остальных узлов. Если не принять специальных мер, в случае отказа узла для фиксации транзакции пришлось бы ждать пока он не будет восстановлен. Чтобы не допустить этого, multimaster периодически опрашивает узлы и проверяет их состояние и соединение между ними. Когда узел не отвечает на несколько контрольных обращений подряд, этот узел убирается из кластера, чтобы оставшиеся в строю узлы могли производить запись. Частоту обращений и таймаут ожидания ответа можно задать в параметрах multimaster.heartbeat_send_timeout и multimaster.heartbeat_recv_timeout, соответственно.

Работающие узлы не имеют возможности отличить отказавший узел, переставший обрабатывать запросы, от узла в недоступной сети, к которому могут обращаться пользователи БД, но не другие узлы. Во избежание конфликтов записи на узлах в разделённых сегментах сети, multimaster разрешает выполнять запись только на тех узлах, которые видят большинство.

Например, предположим, что кластер с пятью ведущими узлами столкнулся с перебоем в сети, в результате которого сеть разделилась на две изолированные подсети так, что в одной оказалось два, а в другой — три узла кластера. На основе информации о доступности узлов multimaster продолжит принимать запросы на запись на всех узлах в большем разделе и запрещать запись в меньшем. Таким образом, кластер, состоящий из 2N+1 узлов может справиться с отказом N узлов и продолжать функционировать пока будут работать и связаны друг с другом N+1 узлов.

В случае частичного разделения сети, когда разные узлы связаны с другими по-разному, multimaster находит подмножество полностью связанных узлов и отключает другие узлы. Например, в кластере с тремя узлами, если узел A может связаться и с B, и с C, а узел B не может связаться с C, multimaster изолирует узел C для обеспечения согласованности данных на узлах A и B.

Каждый узел поддерживает свою структуру данных, в которой учитывает состояние всех узлов относительно него самого. Вы можете получить эту информацию в представлении mtm.get_nodes_state().

Когда ранее отказавший узел возвращается в кластер, multimaster начинает автоматическое восстановление:

  1. Вновь подключённый узел выбирает случайный узел кластера и начинает навёрстывать текущее состояние кластера, используя WAL.

  2. Когда узел синхронизируется до минимальной задержки восстановления, все узлы кластера блокируются на запись (не допускают пишущие транзакции), чтобы процесс восстановления закончился. По умолчанию минимальная задержка восстановления равняется 100 КБ. Это значение можно изменить в переменной multimaster.min_recovery_lag.

  3. По завершении восстановления multimaster повышает вновь подключённый узел, переводит его в рабочее состояние и включает в схему репликации.

Примечание

Автоматическое восстановление возможно, только если отставание в WAL отказавшего угла от работающих не превышает значения multimaster.max_recovery_lag. Если же отставание в WAL оказывается больше значения multimaster.max_recovery_lag, этот узел можно восстановить вручную с одного из работающих узлов, используя pg_basebackup.

См. также

Восстановление узла кластера

F.30.3. Установка и подготовка

Чтобы использовать multimaster, необходимо установить Postgres Pro Enterprise на всех узлах кластера. В состав Postgres Pro Enterprise включены все необходимые зависимости и расширения.

F.30.3.1. Подготовка кластера

Установив Postgres Pro Enterprise на всех узлах, вы должны настроить кластер серверов средствами multimaster.

Предположим, что вам нужно организовать кластер из трёх узлов с доменными именами node1, node2 и node3. Прежде всего разверните базу данных, которая будет реплицироваться, и выберите пользователя с правами суперпользователя для репликации:

  • Если вы делаете всё с нуля, инициализируйте кластер баз данных, создайте пустую базу данных mydb и пользователя myuser на каждом узле кластера. Подробнее об этом можно прочитать в Разделе 17.2.

  • Если у вас уже есть база данных mydb на сервере node1, проинициализируйте новые узлы на основе существующего, используя pg_basebackup. От имени myuser выполните на каждом узле, который вы будете добавлять, следующую команду:

    pg_basebackup -D каталог_данных -h node1 mydb

    Здесь каталог_данных — это каталог, содержащий данные кластера БД. Этот каталог указывается на этапе инициализации кластера или задаётся в переменной окружения PGDATA.

    Более подробно использование pg_basebackup описано в pg_basebackup.

Когда база данных будет готова, выполните следующие действия на всех узлах кластера:

  1. Измените файл конфигурации postgresql.conf следующим образом:

    • Добавьте multimaster в переменную shared_preload_libraries:

      shared_preload_libraries = 'multimaster'

      Подсказка

      Если переменная shared_preload_libaries уже определена в postgresql.auto.conf, вам потребуется изменить её значение с помощью команды ALTER SYSTEM. За подробностями обратитесь к Подразделу 18.1.2.

    • Задайте уровень изоляции транзакций для вашего кластера. В настоящее время multimaster поддерживает уровни read committed и repeatable read.

      default_transaction_isolation = 'read committed'

      Важно

      На уровне repeatable read более вероятны сбои сериализации в момент фиксации. Если ваше приложение не обрабатывает такие сбои, рекомендуется использовать уровень read committed.

    • Установите параметры PostgreSQL, связанные с репликацией.

      wal_level = logical
      max_connections = 100
      max_prepared_transactions = 300
      max_wal_senders = 10       # не меньше количества узлов
      max_replication_slots = 10 # не меньше количества узлов

      Вы должны сменить уровень репликации на logical, так как работа multimaster построена на логической репликации. Для кластера с N узлами разрешите минимум N передающих WAL процессов и слотов репликации. Так как multimaster неявно добавляет фазу PREPARE к COMMIT каждой транзакции, в качестве максимального количества подготовленных транзакций задайте N*max_connections. В противном случае подготовленные транзакции могут ждать выполнения в очереди.

    • Убедитесь в том, что на каждом узле выделено достаточно фоновых рабочих процессов:

      max_worker_processes = 250

      Например, для кластера с тремя узлами и ограничением max_connections = 100 механизму multimaster в пиковые моменты может потребоваться до 206 фоновых рабочих процессов: 200 рабочих процессов для обработки соединений соседних узлов, два — для передатчиков WAL, два — для приёмников WAL и ещё два для процессов-арбитров (передающего и принимающего). При выборе значения этого параметра не забывайте, что фоновые рабочие процессы могут быть нужны и другим модулям.

    • Добавьте параметры, относящиеся к multimaster:

      multimaster.max_nodes = 3  # размер кластера
      multimaster.node_id = 1    # индекс этого узла в кластере,
                                 # начиная с 1
      multimaster.conn_strings = 'dbname=mydb user=myuser host=node1, dbname=mydb user=myuser host=node2, dbname=mydb user=myuser host=node3'
                                 # разделённый запятыми список строк
                                 # подключения к соседним узлам

      Переменная multimaster.max_nodes определяет максимальный размер кластера. Если вы планируете добавлять в кластер новые узлы, значение multimaster.max_nodes должно быть больше начального числа узлов. В этом случае вы сможете добавлять новые узлы, не перезапуская Postgres Pro Enterprise, пока не будет достигнут этот максимум.

      В большинстве случаев для обеспечения высокой степени доступности достаточно трёх узлов. Так как на всех узлах кластера будут одни и те же данные, обычно нет смысла делать более пяти узлов в кластере.

      Если вы хотите изменить параметры соединения по умолчанию для узла кластера, вы можете добавить другие параметры подключения в соответствующую строку подключения в переменной multimaster.conn_strings. Если вы изменили порт по умолчанию, через который процесс-арбитр принимает подключения, вы должны указать этот порт в параметре arbiter_port. За подробностями обратитесь к multimaster.arbiter_port и multimaster.conn_strings.

      Важно

      В переменной multimaster.node_id задаются натуральные числа, начиная с 1, без пропусков в нумерации. Например, для кластера с пятью узлами задайте идентификаторы узлов 1, 2, 3, 4 и 5. При этом важно указывать в переменной multimaster.conn_strings список узлов по порядку их идентификаторов. Значение переменной multimaster.conn_strings должно быть одинаковым на всех узлах.

    В зависимости от вашей схемы использования и конфигурации сети может потребоваться настроить и другие параметры multimaster. За подробностями обратитесь к Подразделу F.30.3.2.

  2. Внесите изменения в файл pg_hba.conf, чтобы пользователь myuser мог осуществлять репликацию на всех узлах кластера.

  3. Перезапустите PostgreSQL:

    pg_ctl -D каталог_данных -l pg.log start

Когда Postgres Pro Enterprise будет запущен на всех узлах, подключитесь к любому зулу и создайте расширение multimaster:

psql -h node1
CREATE EXTENSION multimaster;

Запрос CREATE EXTENSION реплицируется на все узлы кластера.

Чтобы убедиться, что расширение multimaster активно, прочитайте представление mtm.get_cluster_state():

mtm.get_cluster_state();

Если значение liveNodes равняется allNodes, значит ваш кластер успешно настроен и готов к использованию.

См. также

Настройка параметров конфигурации

F.30.3.2. Настройка параметров конфигурации

Хотя вы можете использовать multimaster и в стандартной конфигурации, для более быстрого обнаружения сбоев и более надёжного автоматического восстановления может быть полезно скорректировать несколько параметров.

F.30.3.2.1. Установка таймаута для обнаружения сбоев

Для проверки доступности соседних узлов multimaster периодически опрашивает все узлы. Таймаут для обнаружения сбоев можно регулировать с помощью следующих переменных:

  • Переменная multimaster.heartbeat_send_timeout определяет интервал между опросами. По умолчанию её значение равно 1000ms.

  • Переменная multimaster.heartbeat_recv_timeout определяет интервал для ответа. Если за указанное время ответ от какого-то узла не будет получен, он считается отключённым и исключается из кластера. По умолчанию её значение равно 10000ms.

Значение multimaster.heartbeat_send_timeout имеет смысл выбирать, исходя из типичных задержек ping между узлами. С уменьшением отношения значений recv/send сокращается время обнаружения сбоев, но увеличивается вероятность ложных срабатываний. При установке этого параметра учтите также типичный процент потерь пакетов между узлами кластера.

F.30.3.2.2. Настройка параметров автоматического восстановления

Когда узел кластера на время выходит из строя, multimaster может автоматически восстановить его состояние, используя WAL, собранный на других узлах кластера. Для управления параметрами восстановления предназначены следующие переменные:

  • multimaster.min_recovery_lag — задаёт минимальное расхождение WAL между восстанавливаемым узлом и текущим состоянием кластера. По умолчанию этот параметр равен 100 КБ. Когда ранее отключённый узел достигает состояния, отстающего от текущего на multimaster.min_recovery_lag, multimaster прекращает фиксировать любые транзакции на активных узлах, пока данный узел окончательно не достигнет текущего состояния кластера. Когда данные будут полностью синхронизированы, ранее отключённый узел повышается и становится активным, после чего кластер в целом продолжает работу.

  • multimaster.max_recovery_lag — задаёт максимальный размер WAL. По достижении предела multimaster.max_recovery_lag WAL для отключённого узла будет перезаписан. После этого автоматическое восстановление будет невозможно. В этом случае вы можете восстановить узел вручную, скопировав данные с одного из действующих узлов с помощью pg_basebackup.

По умолчанию значение multimaster.max_recovery_lag равняется 100 МБ. При увеличении multimaster.max_recovery_lag увеличивается окно, в течение которого возможно автоматическое восстановление, но требуется больше места на диске для хранения WAL.

См. также

Переменные GUC

F.30.4. Администрирование кластера multimaster

F.30.4.1. Наблюдение за состоянием кластера

В составе расширения multimaster есть несколько представлений, позволяющих наблюдать за текущим состоянием кластера.

Для проверки свойств определённого узла воспользуйтесь представлением mtm.get_nodes_state():

mtm.get_nodes_state();

Для проверки состояния кластера в целом воспользуйтесь представлением mtm.get_cluster_state():

mtm.get_cluster_state();

Выдаваемая ими информация подробно описана в Подразделе F.30.5.2.

F.30.4.2. Добавление узлов в кластер

Используя расширение multimaster, вы можете добавлять или удалять узлы кластера, не останавливая службу баз данных.

Чтобы добавить узел, необходимо изменить конфигурацию кластера на работающих узлах, загрузить все данные на новом узле, используя pg_basebackup, и запустить этот узел.

Предположим, что у нас есть работающий кластер с тремя узлами с доменными именами node1, node2 и node3. Чтобы добавить node4, следуйте этим указаниям:

  1. Проверьте, не достигает ли текущее число узлов кластера значения, заданного в переменной multimaster.max_nodes. Если это значение достигается, увеличьте multimaster.max_nodes на каждом узле и перезапустите все узлы. Вы можете перезапустить узлы по одному, не останавливая работу всей базы данных. Если предельное число узлов не достигнуто, перейдите к следующему шагу.

  2. Определите, какая строка подключения будет использоваться для обращения к новому узлу. Например, для базы данных mydb, пользователя myuser и нового узла node4 строка подключения может быть такой: "dbname=mydb user=myuser host=node4". За подробностями обратитесь к multimaster.conn_strings.

  3. В psql, подключённом к любому из работающих узлов, выполните:

    mtm.add_node('dbname=mydb user=myuser host=node4');

    Эта команда меняет конфигурацию кластера на всех узлах и запускает слоты репликации для нового узла.

  4. Подключитесь к новому узлу и скопируйте все данные с одного из работающих узлов на новый узел:

    pg_basebackup -D каталог_данных -h node1 -x

    pg_basebackup копирует весь каталог данных с node1, вместе с параметрами конфигурации.

  5. Измените параметры в postgresql.conf на node4:

    multimaster.node_id = 4
    multimaster.conn_strings = 'dbname=mydb user=myuser host=node1, dbname=mydb user=myuser host=node2,
                                dbname=mydb user=myuser host=node3, dbname=mydb user=myuser host=node4'
  6. Запустите PostgreSQL на новом узле:

    pg_ctl -D каталог_данных -l pg.log start

    Все узлы кластера блокируются от записи (не выполняют пишущие транзакции), пока новый узел не получит все изменения, которые имели место после того, как была сделана базовая копия. По завершении восстановления данных multimaster повышает новый узел, переводит его в активное состояние и включает в схему репликации.

Чтобы новая конфигурация была загружена в случае перезапуска PostgreSQL, обновите параметры конфигурации на всех узлах кластера:

  1. Измените параметр multimaster.conn_strings с учётом добавления нового узла.

  2. Разрешите в файле pg_hba.conf репликацию на новый узел.

См. также

Подготовка кластера multimaster

Наблюдение за состоянием кластера

F.30.4.3. Исключение узлов из кластера

Чтобы исключить узел из кластера, воспользуйтесь функцией mtm.stop_node(). Например, чтобы исключить узел 3, запустите следующую команду на любом другом узле:

SELECT mtm.stop_node(3);

В результате будут отключены слоты репликации для узла 3 на всех узлах кластера и репликация на этот узел будет прекращена.

Если вы просто отключите узел, он тоже будет исключён из кластера. Однако все транзакции в кластере будут заморожены некоторое время, пока другие узлы не определят, что он отключён. Этот интервал времени определяется параметром multimaster.heartbeat_recv_timeout.

F.30.4.4. Восстановление узла кластера

Расширение multimaster может автоматически восстановить отказавший узел при наличии WAL на момент времени, когда узел отключился от кластера. Однако, если объём изменений данных на активных узлах превышает допустимый размер WAL, заданный переменной multimaster.max_recovery_lag, автоматическое восстановление невозможно. В этом случае вы можете восстановить отказавший узел вручную.

Предположим, что узел node2 покинул кластер, в котором было три узла, и его нужно восстановить вручную. Типичная процедура восстановления выглядит так:

  1. В psql, подключённом к любому из работающих узлов, создайте слот репликации для отключённого узла, выполнив следующую команду:

    mtm.recover_node(2);

    здесь 2 — идентификатор отключённого узла, заданный в переменной multimaster.node_id.

  2. Подключитесь к узлу node2 и скопируйте все данные с одного из работающих узлов:

    pg_basebackup -D каталог_данных -h node1 -x

    pg_basebackup копирует весь каталог данных с node1, вместе с параметрами конфигурации.

  3. Запустите PostgreSQL на восстановленном узле:

    pg_ctl -D каталог_данных -l pg.log start

    Все узлы кластера блокируются от записи (не выполняют пишущие транзакции), пока восстановленный узел не получит все изменения, которые имели место после того, как была сделана базовая копия. По завершении восстановления данных multimaster повышает новый узел, переводит его в активное состояние и включает в схему репликации.

См. также

Обнаружение сбоя и восстановление

F.30.5. Справка

F.30.5.1. Переменные GUC

multimaster.node_id

Идентификатор узла — натуральное число, однозначно идентифицирующее узел в кластере. Нумерация узлов должна начинаться с 1 и не допускать пропусков. Например, в кластере с пятью узлами они должны иметь идентификаторы 1, 2, 3, 4 и 5.

multimaster.conn_strings

Строки подключения для всех узлов в кластере multimaster, разделённые запятыми. Значение multimaster.conn_strings должно быть одинаковым на всех узлах. Каждая строка подключения должна включать имя реплицируемой базы данных и доменное имя кластера. Например: 'dbname=mydb host=node1, dbname=mydb host=node2, dbname=mydb host=node3'. Дополнительно вы можете добавить другие параметры подключения, переопределяющие параметры по умолчанию. Строки подключения должны указываться в порядке идентификаторов узлов, задаваемых в переменной multimaster.node_id. Строка подключения к i-му узлу должна находиться в i-той позиции. Если вы установили нестандартный порт в переменной multimaster.arbiter_port на каком-либо узле, вы должны задать его в параметре arbiter_port в строке подключения к этому узлу.

multimaster.max_nodes

Максимально допустимое число узлов в кластере. Если вы планируете добавлять в кластер новые узлы, значение multimaster.max_nodes должно быть больше начального числа узлов. В этом случае вы сможете добавлять новые узлы, не перезапуская Postgres Pro Enterprise, пока не будет достигнут этот максимум. В большинстве случаев для обеспечения высокой степени доступности в кластере достаточно трёх узлов. Так как на всех узлах кластера будут одни и те же данные, обычно нет смысла делать более пяти узлов в кластере. Максимально допустимое число узлов не может превышать 64.

По умолчанию число узлов, заданное в переменной multimaster.conn_strings

multimaster.arbiter_port

Порт, через который процесс-арбитр принимает подключения. Если вы меняете значение по умолчанию, вы должны задать его в параметре arbiter_port в строке подключения для соответствующего узла.

По умолчанию: 5433

multimaster.heartbeat_send_timeout

Интервал между контрольными обращениями, в миллисекундах. Процесс-арбитр рассылает широковещательные контрольные сообщения всем узлам для выявления проблем с соединениями.

По умолчанию: 1000

multimaster.heartbeat_recv_timeout

Таймаут, в миллисекундах. Если за это время не поступит ответ на контрольные сообщения, узел будет исключён из кластера.

По умолчанию: 10000

multimaster.min_recovery_lag

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

По умолчанию: 100000

multimaster.max_recovery_lag

Максимальный размер отставания в WAL, в байтах. Когда узел отключается от кластера, другие узлы копируют записи WAL для всех новых транзакций в слот репликации для этого узла. По достижении значения multimaster.max_recovery_lag слот репликации для отключившегося узла удаляется с целью не допустить переполнения. После этого автоматическое восстановление узла становится невозможным. В этом случае вы можете восстановить узел вручную, скопировав данные с одного из работающих узлов, используя pg_basebackup или подобное средство. Если записать в эту переменную ноль, слот не будет удаляться.

По умолчанию: 100000000

multimaster.ignore_tables_without_pk

Логическая переменная. Эта переменная разрешает/запрещает репликацию таблиц, не имеющих первичных ключей. По умолчанию репликация таких таблиц запрещается из-за ограничений логической репликации. Чтобы таблицы без первичных ключей можно было реплицировать, можно задать для этой переменной значение false. Однако учтите, что multimaster не поддерживает операции изменения данных в таких таблицах.

По умолчанию: true

multimaster.cluster_name

Имя кластера. Если вы определяете эту переменную, настраивая кластер, multimaster требует, чтобы это имя было одинаковым на всех узлах кластера.

multimaster.break_connection

Разрывать соединения клиентов, подключённых к узлу, при отключении данного узла от кластера. Если этот параметр равен false, клиенты остаются подключёнными к узлу, но получают ошибку с сообщением о том, что узел оказался в меньшинстве.

По умолчанию: false

multimaster.major_node

Узел с этим флагом продолжает работать, даже если он не может связаться с большинством узлов. Этот флаг необходим для нарушения симметрии в случае наличия в кластере чётного числа активных узлов. Например, кластер с тремя узлами будет продолжать работать при отключении одного из узлов. Если потеряется соединение между оставшимися узлами, узел с флагом multimaster.major_node = true продолжит работать.

Важно

Манипулируя этим параметром, проявляйте осторожность. Установлен этот флаг должен быть только на одном узле. Если он равен true на нескольких узлах, это может привести к проблеме «раздвоения» кластера.

multimaster.max_workers

Максимальное число рабочих процессов walreceiver на этом сервере.

Важно

Манипулируя этим параметром, проявляйте осторожность. Если число одновременных транзакций во всём кластере превышает заданное значение, это может приводить к необнаруживаемым взаимоблокировкам.

multimaster.trans_spill_threshold

Максимальный размер транзакции, в МБ. При достижении этого предела транзакция записывается на диск.

По умолчанию: 100

F.30.5.2. Функции

mtm.get_nodes_state()

Показывает состояние всех узлов в кластере. Возвращает кортеж со следующими значениями:

  • id, integer

    Идентификатор узла.

  • enabled, boolean

    Показывает, не был ли узел исключён из кластера. Узел может быть отключён, если он не откликается на контрольные обращения в течение интервала heartbeat_recv_timeout. Когда узел начинает отвечать на контрольные обращения, multimaster может автоматически восстановить узел и вернуть его в активное состояние. Автоматическое восстановление узла возможно только если сохраняется его слот репликации. В противном случае вы можете восстановить узел вручную.

  • connected, boolean

    Показывает, подключён ли узел к процессу, передающему WAL.

  • slot_active, boolean

    Показывает, активен ли слот репликации для данного узла. Для отключённого узла слот остаётся активным до достижения значения max_recovery_lag.

  • stopped, boolean

    Показывает, была ли остановлена репликация с этим узлом функцией mtm.stop_node(). Остановленный узел находится в том же состоянии, что и отключённый, но он не восстанавливается автоматически. Чтобы повторно активизировать такой узел, нужно вызвать mtm.recover_node().

  • catchUp, boolean

    В процессе восстановления узла показывает, были ли данные восстановлены до значения min_recovery_lag.

  • slotLag, bigint

    Размер данных WAL, которые этот слот репликации сохраняет для отключённого/остановленного узла. Этот слот будет удалён, когда slotLag достигнет значения max_recovery_lag.

  • avgTransDelay, bigint

    Средняя задержка фиксации, вызванная этим узлом, в микросекундах.

  • lastStatusChange, timestamp

    Время, когда этот узел последний раз менял своё состояние (включён/отключён).

  • oldestSnapshot, bigint

    Старейший глобальный снимок, существующий на этом узле.

  • SenderPid, integer

    Идентификатор процесса, передающего WAL.

  • SenderStartTime, timestamp

    Время запуска передатчика WAL.

  • ReceiverPid, integer

    Идентификатор процесса, принимающего WAL.

  • ReceiverStartTime, timestamp

    Время запуска приёмника WAL.

  • connStr, text

    Строка подключения к этому узлу.

  • connectivityMask, bigint

    Битовая маска, представляющая соединения с соседними узлами. Каждый бит представляет соединение с узлом.

  • nHeartbeats, integer

    Число откликов, полученных от этого узла.

mtm.collect_cluster_state()

Собирает данные, возвращаемые функцией mtm.get_cluster_state() со всех доступных узлов. Чтобы эта функция работала, помимо соединений для репликации в pg_hba.conf должны быть разрешены обычные соединения с узлом с заданной строкой подключения.

mtm.get_cluster_state()

Показывает состояние расширения multimaster. Возвращает кортеж со следующими значениями:

  • status, text

    Состояние узла. Возможные значения: Initialization (инициализация), Offline (недоступен), Connected (подключён), Online (работает), Recovery (восстановление), Recovered (восстановлен), InMinor (в меньшинстве), OutOfService (не работает).

  • disabledNodeMask, bigint

    Битовая маска отключённых узлов.

  • disconnectedNodeMask, bigint

    Битовая маска недоступных узлов.

  • catchUpNodeMask, bigint

    Битовая маска узлов, завершивших восстановление.

  • liveNodes, integer

    Число включённых узлов.

  • allNodes, integer

    Число узлов в кластере. Количество активных узлов, составляющих большинство, вычисляется, исходя из этого значения.

  • nActiveQueries, integer

    Число запросов, в настоящее время выполняющихся на этом узле.

  • nPendingQueries, integer

    Число запросов, ожидающих выполнения на этом узле.

  • queueSize, bigint

    Размер очереди ожидающих запросов, в байтах.

  • transCount, bigint

    Общее число реплицированных транзакций, обработанных этим узлом.

  • timeShift, bigint

    Глобальный сдвиг снимка, вызванный рассинхронизацией часов на узлах, в микросекундах.

  • recoverySlot, integer

    Узел, с которого отказавший узел получает обновления данных во время автоматического восстановления.

  • xidHashSize, bigint

    Размер хеша xid2state.

  • gidHashSize, bigint

    Размер хеша gid2state.

  • oldestXid, bigint

    Идентификатор старейшей транзакции на этом узле.

  • configChanges, integer

    Число изменений состояния (включено/отключено) с момента последнего перезапуска.

  • stalledNodeMask, bigint

    Битовая маска узлов, для которых были удалены слоты репликации.

  • stoppedNodeMask, bigint

    Битовая маска узлов, остановленных функцией mtm.stop_node().

  • lastStatusChange, timestamp

    Время последнего изменения состояния.

mtm.add_node(conn_str text)

Добавляет новый узел в кластер.

Аргументы:

  • conn_str — строка подключения для нового узла. Например, для базы данных mydb, пользователя myuser и нового узла node4 строка подключения будет такой: "dbname=mydb user=myuser host=node4".

    Тип: text

mtm.drop_node(node integer, drop_slot bool default false)

Исключает узел из кластера.

Аргументы:

  • node — идентификатор узла, который будет удалён (этот идентификатор задавался в переменной multimaster.node_id).

    Тип: integer

  • drop_slot — Необязательный параметр. Определяет, должен ли вместе с узлом удаляться слот репликации. Передайте в этом параметре true, если вы не планируете восстанавливать этот узел в будущем.

    Тип: boolean

    По умолчанию: false

mtm.recover_node(node integer)

Создаёт слот репликации для узла, который ранее был удалён вместе со своим слотом.

Аргументы:

  • node — идентификатор узла, который нужно восстановить.

mtm.make_table_local(relation regclass)

Останавливает репликацию для указанной таблицы.

Аргументы:

  • relation — Таблица, которую вы хотели бы исключить из схемы репликации.

    Тип: regclass

F.30.6. Совместимость

Расширение multimaster в настоящее время проходит 162 из 166 регрессионных тестов PostgreSQL. В данный момент мы работаем над тем, чтобы обеспечить полную совместимость со стандартным PostgreSQL.

F.30.7. Авторы

Postgres Professional, Москва, Россия.

F.30.7.1. Благодарности

Механизм репликации основан на логическом декодировании и предыдущей версии расширения pglogical, которым поделилась с сообществом команда 2ndQuadrant.

Протокол трёхфазной фиксации транзакций E3PC основан на следующих работах: