Проект

Общее

Профиль

Построение отказоустойчивого кластера СУБД Postgres

Choose a language: RU | EN | ZH

Table of contents

Вы уже знаете, что редакция Tegu Enterprise может хранить базу данных параметров и почту в СУБД Postgres.
Мультисерверная редакция Tegu Enterprise позволяет собрать кластер вычислительных нод Tegu, состоящий из любого количества нод, что позволяет обеспечить отказоустойчивость, а также горизонтально масштабировать мощность сервера. Все они работают симметрично и хранят информацию в СУБД. Однако и сама СУБД может быть собрана по отказоустойчивой схеме. Как это сделать описано в данном разделе.

Обратите внимание, что сборка кластера Postgres не имеет прямого отношения в дистрибутиву Tegu. Тем не менее, данная статья может оказаться полезной в практической реализации решения и потому предлагается вашему вниманию.

Архитектура

  • Три ноды:
    • сервер СУБД - pgc1 (10.1.1.21),
    • сервер СУБД - pgc2 (10.1.1.22),
    • участник кворума pgc3 (10.1.1.23),
  • виртуальный IP - pgc-vip (10.1.1.20).

Установка пакетов

На серверы СУБД необходимо установить сервер PostgreSQL версии не ниже 13.
На все серверы надо установить pcs, необходимый агент fence (fence_pve, fence_virsh, fence_vmware или др.).
Если в репозитории resource-agents-paf версии ниже 2.3.0, то надо скачать отсюда последнюю стабильную версию.

Предварительная подготовка

На всех серверах в файле /etc/hosts должны быть сопоставления имён всех нод с их адресами IP.
Также в этом файле должно быть сопоставление имени для виртуального IP:

10.1.1.20 pgc-vip
10.1.1.21 pgc1.lan pgc1
10.1.1.22 pgc2.lan pgc2
10.1.1.23 pgc3.lan pgc3

Отключаем автозапуск PostgreSQL на серверах СУБД:

systemctl stop postgresql-13.service
systemctl disable postgresql-13.service

Также не забываем убедиться, что в SysV тоже выключено (update-rc.d, chkconfig,...)

Настраиваем репликацию

На сервере pgc1

Если менеджер пакетов не создал системную БД, то надо её создать:

/usr/pgsql-13/bin/postgresql-13-setup initdb

В конец postgresql.conf добавляем параметры:

listen_addresses = '*'
hba_file = '/var/lib/postgresql/13/pg_hba.conf'
include = '../standby.conf'

Файл postgresql.conf может быть либо в /etc/postgresql, либо в в PGDATA (/var/lib/postgresql/13/data).

В файле /var/lib/postgresql/13/standby.conf указываем параметры подключения к мастеру для репликации (это нужно на случай, если она перестанет быть мастером):

primary_conninfo = 'user=repuser host=10.1.1.20 application_name=pgc1'

Переносим pg_hba.conf в папку /var/lib/postgresql/13. Этот файл изначально может быть либо в /etc/postgresql, либо в PGDATA.
В файл pg_hba.conf добавляем запреты и разрешения доступа на репликацию:

host  replication repuser    10.1.1.20/32    reject
local replication all                reject
host  replication all        pgc1        reject
host  replication all        127.0.0.0/8    reject
host  replication all        ::1/128        reject
host  replication all        10.1.1.21/32    reject
host  replication repuser    10.1.1.22/32    trust

Временно назначаем виртуальный IP:
ifconfig eth0:1 10.1.1.20/24

Временно запускаем PostgreSQL:
systemctl start postgresql-13.service

Переходим под системного пользоваеля postgres и создаём роль для репликации:
su - postgres
psql
CREATE USER repuser REPLICATION;

Выходим из psql (Ctrl+D) и из пользователя postgres (Ctrl+D).

На сервере pgc2

Чистим PGDATA:

rm -rf /var/lib/postgresql/13/data/*

Переходим под пользователя postgres и скачиваем реплику с мастера:
su - postgres
pg_basebackup -h pgc-vip -U repuser -D /var/lib/postgresql/13/data -X stream -P

В файле /var/lib/postgresql/13/standby.conf указываем параметры подключения к мастеру для репликации:

primary_conninfo = 'user=repuser host=10.1.1.20 application_name=pgc2'

Создаём файл /var/lib/postgresql/13/pg_hba.conf с таким же содержимым, как и на pgc1, но меняем следующие строки:

host  replication all        pgc1            reject

Меняем на:
host  replication all        pgc2            reject

host  replication all        10.1.1.21/32    reject

Меняем на:
host  replication all        10.1.1.22/32    reject

host  replication repuser    10.1.1.22/32    trust

Меняем на:
host  replication repuser    10.1.1.21/32    trust

Указываем, что это подчинённый сервер:

touch /var/lib/postgresql/13/data/standby.signal

Выходим из пользователя postgres (Ctrl+D).

На сервере pgc1

Останавливаем PostgreSQL:

systemctl stop postgresql-13.service

Убираем виртуальный IP:
ifconfig eth0:1 0.0.0.0

Настройка кластера

Для начала на всех серверах надо задать один и тот же пароль для пользователя hacluster:

passwd hacluster

Включаем и запускаем демон pcsd на всех нодах:
systemctl enable --now pcsd

На каждой ноде запускаем авторизацию с остальными:

pcs host auth -u hacluster pgc1 pgc2 pgc3

Создаём кластер, выполнив следующее на первой ноде (pgc1):

pcs cluster setup pgsql_cluster pgc1 pgc2 pgc3

Чтобы не было никаких неожиданных спец.эффектов после перезапуска нод, отключаем автозапуск pacemaker-а. На каждой ноде:

pcs cluster disable --all

На сервере pgc1

Включаем кластер:

pcs cluster start --all

Задаём параметры по умолчанию:

pcs resource defaults migration-threshold=5
pcs resource defaults resource-stickiness=10

Создаём устройства ограждения (fencing). Здесь приводятся устройства для Proxmox, но в других конфигурациях могут быть другие. Для конкретного типа надо смотреть доку по параметрам:

pcs cluster cib fencing.xml
pcs -f fencing.xml stonith create fence_vm_pgc1 fence_pve pcmk_host_list="pgc1" pcmk_host_check="static-list" ipaddr="10.1.1.199" node_name="vrt1" login="fenceuser@pve" passwd="Qwe123Poi" port="101" power_wait="10" vmtype="lxc" 
pcs -f fencing.xml stonith create fence_vm_pgc2 fence_pve pcmk_host_list="pgc2" pcmk_host_check="static-list" ipaddr="10.1.1.199" node_name="vrt1" login="fenceuser@pve" passwd="Qwe123Poi" port="102" power_wait="10" vmtype="lxc" 
pcs -f fencing.xml stonith create fence_vm_pgc3 fence_pve pcmk_host_list="pgc3" pcmk_host_check="static-list" ipaddr="10.1.1.199" node_name="vrt1" login="fenceuser@pve" passwd="Qwe123Poi" port="103" power_wait="10" vmtype="lxc" 

Здесь:
  • 10.1.1.199 - адрес любой достуной ноды Proxmox,
  • node_name="vrt1" - имя ноды (точно, как указано в самом Proxmox),
  • fenceuser@pve - пользователь Proxmox, который имеет право перезапускать, запускать и останавливать данные ВМ,
  • port="101" - vmid виртуалки, для которой создаётся устройство (берётся в Proxmox),
  • vmtype="lxc" - тип виртуалки (в данном случае - контейнер LXC).

Указываем для каждой ноды, что её устройство ограждения на ней же самой сработать не может (сами в себя не стреляем):

pcs -f fencing.xml constraint location fence_vm_pgc1 avoids pgc1=INFINITY
pcs -f fencing.xml constraint location fence_vm_pgc2 avoids pgc2=INFINITY
pcs -f fencing.xml constraint location fence_vm_pgc3 avoids pgc3=INFINITY

И применяем конфигурацию:
pcs cluster cib-push scope=configuration fencing.xml

Создаём ресурс PostgreSQL:

pcs cluster cib cluster1.xml
pcs -f cluster1.xml resource create pgsqld ocf:heartbeat:pgsqlms \
 bindir=/usr/lib/postgresql/13/bin \
 pgdata=/var/lib/postgresql/13/data \
 pghost=/var/run/postgresql \
 op start timeout=60s \
 op stop timeout=60s \
 op promote timeout=30s \
 op demote timeout=120s \
 op monitor interval=15s timeout=10s role="Master" \
 op monitor interval=16s timeout=10s role="Slave" \
 op notify timeout=60s \
 promotable notify=true

Здесь:
  • bindir - папка с бинарниками PostgreSQL (нужен pg_ctl),
  • pgdata - PGDATA,
  • pghost - папка, где PostgreSQL создаёт unix-сокет (файл с именем .s.PGSQL.5432).

Запрещаем этому ресурсу запускаться на сервере участнике кворума (pgc3):

pcs -f cluster1.xml constraint location pgsqld-clone rule resource-discovery=never score=-INFINITY \#uname eq pgc3

Создаём ресурс виртуального IP:

pcs -f cluster1.xml resource create pgsql-pri-ip ocf:heartbeat:IPaddr2 ip=10.1.1.20 cidr_netmask=24 op monitor interval=10s

Привязываем этот ресурс к предыдущему и задаём порядок запуска ресурсов и их остановки:

pcs -f cluster1.xml constraint colocation add pgsql-pri-ip with master pgsqld-clone INFINITY
pcs -f cluster1.xml constraint order promote pgsqld-clone then start pgsql-pri-ip symmetrical=false kind=Mandatory
pcs -f cluster1.xml constraint order demote pgsqld-clone then stop pgsql-pri-ip symmetrical=false kind=Mandatory

Применяем конфигурацию:

pcs cluster cib-push scope=configuration cluster1.xml

Через несколько секунд будут запущены все ресурсы.

Мониторим командой crm_mon на любой ноде.