Представь, что твоё приложение растёт, и нагрузка на базу данных становится критической. Одиночный сервер PostgreSQL уже не справляется. Решение — кластеризация. В этой статье мы разберём, как выполнить установку кластера PostgreSQL и его тонкую настройку для обеспечения высокой доступности и отказоустойчивости. Давай превратим несколько серверов в слаженную систему.
Что такое кластер PostgreSQL и зачем он нужен?
Кластер PostgreSQL — это группа серверов (нод), работающих совместно для обеспечения отказоустойчивости, балансировки нагрузки и горизонтального масштабирования чтения. Основные архитектуры:
- Master-Slave (Primary-Standby): Одна нода принимает запись, остальные — реплики для чтения и горячего резерва.
- Multi-Master: Несколько нод могут принимать запись (требует дополнительных решений, например, на основе логической репликации или сторонних инструментов).
Подготовка к установке кластера PostgreSQL
Перед началом настройки кластера postgresql определимся с инфраструктурой. Нам понадобятся как минимум две виртуальные машины или физических сервера.
Требования к инфраструктуре
- Сервера (ноды): 2 или более. Назовём их
pg-primary(192.168.1.10) иpg-replica(192.168.1.11). - ОС: Ubuntu 22.04 LTS / CentOS 8 / аналогичные.
- Сеть: Стабильное соединение с низкой задержкой между нодами. Настроенный разрешённый трафик на портах 5432 (PostgreSQL) и 22 (SSH).
- Диски: Желательно SSD с одинаковой производительностью на всех нодах.
chronyd или ntpd). Рассинхронизация может сломать репликацию.
Пошаговая установка и настройка кластера PostgreSQL
Теперь перейдём к практической части. Мы выполним установку PostgreSQL, базовую конфигурацию и настроим потоковую репликацию (Streaming Replication).
Шаг 1: Установка PostgreSQL на все ноды
Выполни эти команды на ОБОИХ серверах (primary и replica).
# Для Ubuntu/Debian
sudo apt update
sudo apt install -y postgresql-15 postgresql-contrib-15
# Для CentOS/RHEL/Rocky Linux
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo dnf -qy module disable postgresql
sudo dnf install -y postgresql15-server postgresql15-contrib
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
sudo systemctl enable postgresql-15
# Проверь, что служба запущена
sudo systemctl status postgresql-15
Шаг 2: Настройка Primary-сервера (мастера)
Теперь сконфигурируем главную ноду. Основные файлы конфигурации находятся в /etc/postgresql/15/main/ (Ubuntu) или /var/lib/pgsql/15/data/ (CentOS).
1. Редактируем postgresql.conf:
# Найдите и измените следующие параметры:
listen_addresses = '*' # Разрешаем подключения со всех IP
port = 5432 # Стандартный порт
max_connections = 100 # Подстрой под свои нужды
wal_level = replica # Обязательно для репликации!
max_wal_senders = 10 # Количество одновременно работающих реплик
wal_keep_size = 1024 # Минимум 1GB WAL файлов для реплик
hot_standby = on # Разрешаем чтение на репликах (для будущего)
2. Редактируем pg_hba.conf: Добавляем запись, разрешающую подключение реплики для репликации.
# Добавь в конец файла строку:
# TYPE DATABASE USER ADDRESS METHOD
host replication replicator 192.168.1.11/32 scram-sha-256
# Также убедись, что есть доступ для твоего приложения с рабочих IP.
3. Создаём пользователя для репликации: Подключись к PostgreSQL и выполни SQL.
sudo -u postgres psql
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'StrongPassword123!';
\du+ replicator -- Проверь создание пользователя
4. Перезапускаем PostgreSQL на primary:
sudo systemctl restart postgresql-15
Шаг 3: Настройка Replica-сервера (реплики)
Теперь настроим ведомую ноду. Сначала останови PostgreSQL на replica и удали данные по умолчанию.
sudo systemctl stop postgresql-15
sudo rm -rf /var/lib/postgresql/15/main/* # Ubuntu
# ИЛИ
sudo rm -rf /var/lib/pgsql/15/data/* # CentOS
Ключевой момент: Используем утилиту pg_basebackup для создания начальной копии данных с мастера.
# Выполни на реплике от пользователя postgres:
sudo -u postgres pg_basebackup -h 192.168.1.10 -D /var/lib/postgresql/15/main -U replicator -P -v -R -X stream -C -S pg_replica_slot1
# Разбор ключей:
# -h Адрес primary-сервера
# -D Целевая директория с данными
# -U Пользователь для репликации
# -P Прогресс-бар
# -v Подробный вывод
# -R Автоматическое создание standby.signal и настройка в postgresql.auto.conf
# -X stream Потоковая передача WAL во время бэкапа
# -C Создание слота репликации
# -S Имя слота репликации
После успешного выполнения команды в директории данных реплики появятся все файлы с primary, а также два ключевых файла:
standby.signal— сигнализирует PostgreSQL, что это реплика.postgresql.auto.conf— содержит параметры подключения к мастеру.
Запускаем PostgreSQL на реплике:
sudo systemctl start postgresql-15
sudo systemctl status postgresql-15 # Проверяем статус
Шаг 4: Проверка работы репликации
Давай убедимся, что кластер работает корректно.
На Primary-сервере:
sudo -u postgres psql
-- Проверяем подключённые реплики
SELECT client_addr, state, sync_state, replay_lag FROM pg_stat_replication;
-- Создадим тестовую базу и таблицу для проверки
CREATE DATABASE cluster_test;
\c cluster_test
CREATE TABLE test_table (id serial, data text);
INSERT INTO test_table (data) VALUES ('Data from primary');
На Replica-сервере:
sudo -u postgres psql
-- Проверяем, что мы в режиме standby
SELECT pg_is_in_recovery();
-- Должно вернуть 't' (true)
-- Проверяем тестовые данные (чтение должно работать!)
\c cluster_test
SELECT * FROM test_table;
-- Попробуем записать (должна быть ошибка)
INSERT INTO test_table (data) VALUES ('This will fail');
-- Ошибка: cannot execute INSERT in a read-only transaction
Углублённая настройка и оптимизация кластера
Базовая установка кластера postgresql завершена. Теперь давай сделаем его production-готовым.
Настройка мониторинга репликации
Создадим представление для удобного мониторинга лага репликации на primary.
CREATE VIEW pg_replication_status AS
SELECT
client_addr,
application_name,
state,
sync_state,
pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS sent_lag_bytes,
pg_wal_lsn_diff(sent_lsn, flush_lsn) AS flush_lag_bytes,
pg_wal_lsn_diff(flush_lsn, replay_lsn) AS replay_lag_bytes,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS total_lag_bytes,
to_char(now() - reply_time, 'HH24:MI:SS') AS replication_delay
FROM pg_stat_replication;
-- Использование:
SELECT * FROM pg_replication_status;
Настройка автоматического переключения при отказе (Failover)
Ручное переключение — это риск. Рассмотрим использование Patroni — популярного инструмента для управления кластерами PostgreSQL.
# Установка Patroni на всех нодах (пример для Ubuntu)
sudo apt install -y python3-pip etcd
sudo pip3 install patroni[etcd] python-consul
# Создание конфигурационного файла /etc/patroni.yml
# Конфиг включает настройки PostgreSQL, DCS (Distributed Configuration Store, например, etcd) и условия для failover.
Patroni автоматически управляет ролями нод, переключает primary при сбоях и поддерживает актуальность конфигурации.
Сравнение методов репликации
| Метод | Синхронная | Асинхронная | Логическая |
|---|---|---|---|
| Надёжность данных | Максимальная | Высокая | Выборочная |
| Задержка (lag) | Нет (0) | Несколько секунд | Зависит от нагрузки |
| Влияние на primary | Высокое (ждёт подтверждения) | Минимальное | Среднее |
| Использование | Финансовые системы | Большинство web-приложений | Апгрейд версий, отчёты |
Чтобы включить синхронную репликацию, на primary в postgresql.conf укажи:
synchronous_standby_names = 'pg_replica_slot1'
Частые проблемы и их решение (FAQ)
Репликация остановилась, в логах "FATAL: could not receive data from WAL stream"
Причина: Чаще всего — закончилось место для WAL-файлов на primary или реплика слишком долго отставала и нужные WAL-файлы были удалены.
Решение:
- Увеличь параметр
wal_keep_sizeвpostgresql.confна primary. - Настрой архивацию WAL-файлов (
archive_mode = on). - Если реплика «сломана», проще пересоздать её заново с помощью
pg_basebackup.
Как добавить ещё одну реплику в работающий кластер?
Процесс аналогичен первоначальной настройке второй реплики. Просто выполни шаг 3 (настройка replica-сервера) на новом хосте, указав в команде pg_basebackup актуальный IP primary. Не забудь добавить запись для нового IP в pg_hba.conf на primary и перезагрузить конфиг (SELECT pg_reload_conf();).
Можно ли настроить балансировку нагрузки на чтение?
Да! После настройки нескольких реплик можно использовать:
- Pgpool-II: Прокси-сервер, который умеет балансировать запросы на чтение между репликами, а запись направлять на primary.
- HAProxy: Универсальный балансировщик. Настрой два бэкенда: один для записи (только primary), второй для чтения (все реплики). Определяй тип запроса на уровне приложения.
Как выполнить плановое переключение ролей (switchover)?
1. На реплике, которую хочешь сделать новым primary, создай триггер файл: sudo -u postgres touch /var/lib/postgresql/15/main/promote.trigger.
2. PostgreSQL на этой ноде выйдет из режима standby и станет primary.
3. На старом primary необходимо настроить репликацию на новый primary (процесс, обратный изначальной настройке).
Совет: Для production используй Patroni или repmgr, которые автоматизируют этот процесс.
Заключение
Мы детально разобрали процесс установки кластера PostgreSQL и его базовой настройки. Ты научился:
- Готовить инфраструктуру для кластера.
- Настраивать потоковую репликацию между primary и standby нодами.
- Проверять корректность работы репликации.
- Понимать различия между синхронной и асинхронной репликацией.
- Знакомиться с инструментами для автоматизации failover (Patroni).
Помни, что настройка кластера postgresql — это только первый шаг. Дальнейшие этапы — это настройка мониторинга (например, с помощью Prometheus и pg_exporter), резервного копирования с учётом кластерной архитектуры и отработка процедур аварийного восстановления. Начни с тестового стенда, отточи все операции, и только затем переноси кластер в production.