Настройка синхронной репликации для высокой доступности в PostgreSQL

Научитесь настраивать высокую доступность PostgreSQL с нулевой потерей данных (RPO=0) с использованием синхронной потоковой репликации. Это пошаговое руководство охватывает основные конфигурации для `wal_level`, слотов репликации, `pg_basebackup`, а также правильную настройку параметров `synchronous_commit` на основном и резервном серверах для обеспечения долговечности транзакций в критически важных средах.

33 просмотров

Настройка синхронной репликации для обеспечения высокой доступности в PostgreSQL

Настройка PostgreSQL для высокой доступности (HA) критически важна для любого критически важного приложения. Хотя асинхронная репликация предлагает преимущества в производительности, она по своей природе несет риск потери данных, если основной сервер выйдет из строя до того, как изменения будут полностью переданы резервному серверу. Синхронная потоковая репликация решает эту проблему, гарантируя, что транзакция считается зафиксированной только после того, как данные были успешно записаны в WAL (журнал предзаписи) как основного, так и по крайней мере одного назначенного резервного сервера. Это обеспечивает нулевую целевую точку восстановления (RPO).

Это исчерпывающее руководство проведет вас через основные шаги по настройке, необходимые для создания надежной конфигурации репликации PostgreSQL с нулевой потерей данных. Мы сосредоточимся на таких критически важных параметрах, как wal_level и synchronous_commit, которые лежат в основе этой архитектуры высокой доступности.

Предварительные условия

Прежде чем начать, убедитесь, что у вас настроены два сервера PostgreSQL (основной и резервный), работающие с одинаковыми основными версиями PostgreSQL. Оба сервера должны иметь сетевое соединение. Для этого руководства мы предполагаем:

  • Имя хоста/IP основного сервера: pg_primary
  • Имя хоста/IP резервного сервера: pg_standby
  • Пользователь репликации: repl_user (создан с соответствующими разрешениями)
  • Имя базы данных: mydb

Шаг 1: Настройка основного сервера

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

А. Изменение postgresql.conf на основном сервере

Отредактируйте файл postgresql.conf основного сервера. Следующие параметры обязательны для потоковой репликации:

# --- Требуется для репликации ---
listen_addresses = '*'         # Разрешает подключения с резервного сервера
wal_level = replica            # Должен быть 'replica' или выше (например, 'logical')
max_wal_senders = 10           # Максимальное количество одновременных подключений с резервных серверов
max_replication_slots = 10     # Слоты, необходимые для постоянных потоков репликации

# --- Существенно для синхронной фиксации ---
synchronous_standby_names = '1 (standby_app_name)' # Указывает требуемые резервные серверы

# --- Необязательно, но рекомендуется ---
wal_log_hints = on             # Рекомендуется для более безопасной репликации, хотя увеличивает объем WAL
shared_preload_libraries = 'pg_stat_statements' # При использовании мониторинга

Пояснение ключевых параметров:

  • wal_level = replica: Это гарантирует, что в WAL записывается достаточно информации, чтобы резервный сервер мог восстановить состояние базы данных. Для синхронных фиксаций этот уровень является минимальным требованием.
  • synchronous_standby_names: Это основная настройка для определения того, какие резервные серверы должны подтвердить запись. Мы определяем ее с использованием синтаксиса (N (standby_name)). Если N=1, по крайней мере один резервный сервер должен подтвердить запись до фиксации транзакции.

Б. Настройка аутентификации на основе хостов (pg_hba.conf)

Основной сервер должен разрешить пользователю репликации с резервного сервера(ов) подключаться для целей репликации.

Добавьте запись в pg_hba.conf на основном сервере:

# ТИП  БАЗА ДАННЫХ      ПОЛЬЗОВАТЕЛЬ    АДРЕС                   МЕТОД
host    replication     repl_user       pg_standby/32           scram-sha-256

Замените pg_standby/32 фактическим IP-адресом или подсетью вашего резервного сервера.

В. Создание слота репликации и пользователя

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

1. Создайте пользователя репликации:

CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'a_strong_password';

2. Создайте слот репликации:

Этот слот гарантирует, что сегменты WAL сохраняются до тех пор, пока резервный сервер не подтвердит получение, предотвращая потерю данных, если резервный сервер временно отключится.

SELECT pg_create_physical_replication_slot('standby_app_name');
  • Примечание по именованию: Имя, указанное здесь (standby_app_name), должно соответствовать имени, указанному в synchronous_standby_names на основном сервере.

Г. Перезапуск основного сервера

Примените все изменения конфигурации, перезапустив службу PostgreSQL на основном сервере.

sudo systemctl restart postgresql

Шаг 2: Настройка резервного сервера

Резервный сервер настраивается для потоковой передачи записей WAL с основного сервера с использованием конфигурации восстановления.

А. Базовое резервное копирование

Прежде чем начать потоковую передачу, резервному серверу нужна полная копия каталога данных основного сервера. Сначала остановите PostgreSQL на резервном сервере.

sudo systemctl stop postgresql

Выполните базовое резервное копирование с помощью pg_basebackup. Замените пути и данные подключения по мере необходимости:

# Пример использования утилиты pg_basebackup
pg_basebackup -h pg_primary -D /var/lib/postgresql/15/main/ -U repl_user -P -Xs -R -W
  • -D: Целевой каталог данных на резервном сервере.
  • -U: Пользователь репликации.
  • -P: Показать прогресс.
  • -Xs: Включить необходимые файлы WAL во время базового резервного копирования.
  • -R: Автоматически создать файл standby.signal и сгенерировать необходимые настройки подключения в postgresql.auto.conf (или конфигурацию восстановления).

Б. Настройка postgresql.conf на резервном сервере

На резервном сервере убедитесь, что postgresql.conf разрешает ему действовать как реплика. Ключевой настройкой здесь является установка имени приложения, которое должно соответствовать имени слота, используемому на основном сервере.

# --- Требуется на резервном сервере ---
primary_conninfo = 'host=pg_primary port=5432 user=repl_user password=a_strong_password application_name=standby_app_name'
hot_standby = on          # Разрешает запросы на чтение в режиме восстановления/резерва

В. Запуск резервного сервера

Запустите службу PostgreSQL на резервном сервере.

sudo systemctl start postgresql

Шаг 3: Проверка и тестирование синхронной фиксации

После запуска обоих серверов проверьте соединение, а затем протестируйте синхронное поведение.

А. Проверка состояния репликации

Подключитесь к базе данных основного сервера и проверьте представление pg_stat_replication:

SELECT client_addr, application_name, state, sync_state FROM pg_stat_replication;

Вы должны увидеть запись для standby_app_name со значением sync_state как sync.

Б. Тестирование синхронной фиксации

Глобальный параметр, который определяет, насколько строго PostgreSQL ждет, — это synchronous_commit. Для RPO=0 вы должны использовать значение, которое принуждает к синхронизации.

1. Настройка глобального поведения

Если вы настроили synchronous_standby_names на основном сервере, как показано в Шаге 1, поведение по умолчанию будет принуждать к ожиданию необходимых резервных серверов, если synchronous_commit установлен в on (по умолчанию) или remote_write.

Для максимально сильной гарантии явно установите его в postgresql.conf на remote_write или remote_apply (если вам нужно, чтобы резервный сервер сбросил данные на диск, а не только получил их).

# В postgresql.conf на основном сервере
synchronous_commit = remote_write

Предупреждение: Установка synchronous_commit = remote_write или on значительно увеличивает задержку транзакций по сравнению с асинхронными режимами (off или local). Эта задержка напрямую коррелирует со скоростью сети между основным и синхронным резервным сервером.

2. Тестирование внутри транзакции

Чтобы протестировать транзакционно (без необходимости изменения глобальной конфигурации), вы можете установить его для сессии или транзакции:

-- Подключение к основному серверу

BEGIN;
SET LOCAL synchronous_commit = remote_write;

INSERT INTO sales (item, amount) VALUES ('Widget A', 100);
-- Эта операция INSERT будет заблокирована, пока 'standby_app_name' не подтвердит получение.

COMMIT;
-- COMMIT завершается успешно только после того, как резервный сервер подтвердит запись WAL.

Если соединение с синхронным резервным сервером потеряно во время транзакции, основной сервер либо будет ждать бесконечно (если резервный сервер отключается корректно), либо откатится на основе настройки synchronous_commit_fallback_on_error (по умолчанию on, что означает, что транзакция может завершиться неудачно или зависнуть, если основной сервер не может подтвердить статус синхронизации).

Лучшие практики для синхронной высокой доступности

  • Используйте выделенные резервные серверы: Назначайте в свой список синхронной репликации только те резервные серверы, которые физически расположены близко (низкая задержка) к основному. Высокая задержка серьезно повлияет на производительность записи.
  • Мониторинг задержки репликации: Даже в синхронном режиме отслеживайте задержку резервного сервера. Медленный резервный сервер, который все еще технически 'синхронизирован', но слишком долго обрабатывает WAL, все равно может повлиять на пользовательский опыт.
  • Откат соединения: Поймите настройку synchronous_commit_fallback_on_error. Если установлено off, сбой связи с синхронным резервным сервером во время фиксации приведет к сбою транзакции на основном сервере, предотвращая потенциальное расхождение данных, но немедленно влияя на доступность.
  • Используйте несколько резервных серверов: Для максимальной избыточности в синхронной настройке настройте synchronous_standby_names = '2 (standby1, standby2)', чтобы требовать фиксации от двух разных резервных серверов.