В статье расскажу про мой опыт настройки Postgresql для работы под контролем кластерной службы PacemakerПод нагрузкой данное решение не проверялось, всегда делайте (и проверяйте) резервные копии.
Для хранения базы данных будет рассмотрен пример использования кластерной файловой системе OCFS2.
Версии ПО, использованные в примере:
*** OCFS2 - драйвер из ядра 5.10, утилиты ocfs2-tools - 1.8.6
*** Corosync - 3.1.2
*** Pacemaker - 2.0.5
*** Postgresql 13В статье будет три типа кластеров:
*** кластер файловой системы OCFS2 - обеспечивает хранение файлов на общем диске и согласованную работу с ними
*** кластер Corosync/Pacemaker - обеспечивает отслеживание работы процессов СУБД, запуск виртуального ip-адреса СУБД
*** кластер баз данных Postgresql - набор баз, управляемых одним экземпляром работающего сервера СУБД++ Подготовка операционных систем
Для устойчивой работы кластеров (OCFS2, Pacemaker/Corosync) необходимо как минимум три сервера. Сервера могут быть как физические так и виртуальные. Желательно, чтобы сервера имели одинаковые характеристики производительности.
Я для демонстрации подготовил три виртуальные машины с помощью Qemu-KVM.
Устанавливаем ОС Debian 11 на каждый из серверов в минимальной конфигурации.
++ Настройка сети
В примере у меня будут сервера с адресами:
*** node1 - ip 192.168.1.11
*** node2 - ip 192.168.1.12
*** node3 - ip 192.168.1.13Имена узлов должны разрешаться в IP-адреса на каждом из серверов, для этого необходимо прописать сопоставление в файле /etc/hosts или создать записи на DNS-сервере.
root:~# cat /etc/hosts
127.0.0.1 localhost
192.168.1.11 node1.local node1
192.168.1.12 node2.local node2
192.168.1.13 node3.local node3В случае реальной реализации кластера, сетевых карт на каждом из серверов должно быть как минимум две - карты необходимо объединить в логическое устройство bonding или teaming. Физически карты должны подключаться к двум независимым коммутаторам. В примере у меня будет по одной сетевой карте на сервер.
++ Настройка сетевого экрана
Выполняем настройку экрана на каждом узле:
*** устанавливаем пакет для управления брандмауэром ufw
*** создаём разрешающие правила для ssh, postgres, узлов кластера
*** активируем правилаroot# apt install ufw
root# ufw allow ssh
root# ufw allow postgres
root# ufw allow from 192.168.1.11 to any
root# ufw allow from 192.168.1.12 to any
root# ufw allow from 192.168.1.13 to any
root# ufw enableКластер OCFS2 для отслеживания работы узлов по-умолчанию использует протокол TCP порт 7777 (задаётся в файле /etc/ocfs2/cluster.conf), а Corosync - протокол UDP, порт 5405 (задаётся в файле /etc/corosync/corosync.conf), с учётом этого, можно настроить более тонкие правила брандмауэра:
root# ufw allow proto tcp from 192.168.1.11 to any port 7777
root# ufw allow proto tcp from 192.168.1.12 to any port 7777
root# ufw allow proto tcp from 192.168.1.13 to any port 7777
root# ufw allow proto udp from 192.168.1.11 to any port 5405
root# ufw allow proto udp from 192.168.1.12 to any port 5405
root# ufw allow proto udp from 192.168.1.13 to any port 5405++ Настройка дисковой системы
На каждом сервере будет индивидуальный диск для системы (/dev/vda, 20 Гб) и общий диск на все сервера для хранения БД (/dev/vdb, 5 Гб):
root# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 254:0 0 20G 0 disk
├─vda1 254:1 0 512M 0 part /boot/efi
├─vda2 254:2 0 18,5G 0 part /
└─vda3 254:3 0 976M 0 part [SWAP]
vdb 254:16 0 5G 0 disk /mnt/ocfs2clst++ Настройка кластерной файловой системы
Для реального использования общий диск должен быть расположен на системе хранения данных, и подключатся к серверам по нескольким путям.
Для демонстрации общий диск будет реализован с помощью средств Qemu-KVM.
++ Настройка службы кластера ФС OCFS2
++ Настройка ядра Linux
Необходимо изменить параметры ядра, чтобы сервер автоматически перезагружался при сбое кластерной ФС, для это нужно создать файл /etc/sysctl.d/10-ocfs2.conf
kernel.panic_on_oops = 1
kernel.panic = 30После применить параметры:
root# systemctl restart systemd-sysctl
Данные настройки указывают ядру Linux при возникновении сбоя (когда связь по сети пропала, но узел продолжает запись heartbeat сообщений на общий диск) автоматически перезагрузить узел через 30 секунд.
++ Установка пакетов OCFS2
Устанавливаем пакеты на каждом из узлов
root# apt install ocfs2-tools
++ Настройка кластера ФС OCFS2
Все настройки кластера OCFS2 хранятся в файле /etc/ocfs2/cluster.conf.
Нужно либо выполнить команды на каждом узле кластера, либо выполнить на одном узле и после скопировать файл /etc/ocfs2/cluster.conf на каждый узел, а после выполнить регистрацию и запуск.
Создаём кластер (выполнить на каждом узле кластера)
root# o2cb add-cluster ocfs2clst
Добавляем узлы в кластер (выполнить на каждом узле кластера), имя узла должно совпадать с тем, что выдаёт команда hostname
root# o2cb add-node --ip 192.168.1.11 --port 7777 --number 1 ocfs2clst node1
root# o2cb add-node --ip 192.168.1.12 --port 7777 --number 2 ocfs2clst node2
root# o2cb add-node --ip 192.168.1.13 --port 7777 --number 3 ocfs2clst node3Регистрируем кластер (выполнить на каждом узле кластера)
root# o2cb register-cluster ocfs2clst
Включаем кластер (выполнить на каждом узле кластера)
root# o2cb start-heartbeat ocfs2clst
Выполняем настройку драйвера ФС (обязательно выполнить на каждом узле кластера)
root# dpkg-reconfigure ocfs2-tools
Запускать кластер OCFS2 (O2CB) во время загрузки компьютера?: Y
Имя кластера, запускаемого во время загрузки компьютера: ocfs2clstНастройки драйвера хранятся в файле /etc/default/o2cb
Содержимое файла:
# O2CB_ENABLED: 'true' means to load the driver on boot.
O2CB_ENABLED=true
# O2CB_BOOTCLUSTER: If not empty, the name of a cluster to start.
O2CB_BOOTCLUSTER=ocfs2clst
# O2CB_HEARTBEAT_THRESHOLD: Iterations before a node is considered dead.
O2CB_HEARTBEAT_THRESHOLD=31
# O2CB_IDLE_TIMEOUT_MS: Time in ms before a network connection is considered dead.
O2CB_IDLE_TIMEOUT_MS=30000
# O2CB_KEEPALIVE_DELAY_MS: Max. time in ms before a keepalive packet is sent.
O2CB_KEEPALIVE_DELAY_MS=2000
# O2CB_RECONNECT_DELAY_MS: Min. time in ms between connection attempts.
O2CB_RECONNECT_DELAY_MS=2000++ Создание ФС OCFS2
Можно создать разделы на кластерном томе и создавать ФС уже на разделе, но это добавит сложностей при расширении тома, так как придётся вручную править границы раздела с помощью parted/fdisk и после расширять ФС. Но у нас кластерный том планируется целиком отдать под работу СУБД Postgresql, поэтому ФС предлагаю создать сразу на всем томе (в примере это диск /dev/vdb).
Выполняем форматирование общего тома на одном из узлов:
root# mkfs.ocfs2 -L pg-data --cluster-name=ocfs2clst -N 5 -T datafiles --fs-feature-level=max-features --cluster-stack=o2cb /dev/vdb
Описание параметров:
*** -L pg-data - метка ФС
*** --cluster-name=ocfs2clst - имя кластера OCFS2, который управляет ФС
*** -N 5 - максимальное количество узлов, которые могут работать одновременно с ФС, позже можно поменять с помощью tunefs.ocfs2, но рекомендуется создавать структуру заранее
*** -T datafiles - тип хранимых данных, может быть mail, datafiles, vmstore
*** --fs-feature-level=max-features - включаем все доступные возможности ФС, т.к. узлы у нас идентичные
*** --cluster-stack=o2cb - используем для управления ФС стандартный стек o2cbПроверяем, что метки новой ФС видны на всех узлах кластера:
root# blkid /dev/vdb
/dev/vdb: LABEL="pg-data" UUID="ce92b1e7-30cb-4883-9a92-57c986f76acd" BLOCK_SIZE="4096" TYPE="ocfs2"Вывод команды blkid на всех узлах кластера должен совпадать.
++ Выполняем пробное монтирование
Монтирование выполняется 20-30 секунд, так как требует согласования по сети. Выполняем команды на всех узлах кластера.
root# mkdir /mnt/ocfs2clst
root# mount /dev/disk/by-uuid/ce92b1e7-30cb-4883-9a92-57c986f76acd /mnt/ocfs2clstКоманда mounted.ocfs2 показывает на каких узлах смонтирована ФС.
root# mounted.ocfs2 -f
Device Stack Cluster F Nodes
/dev/vdb o2cb ocfs2clst node1, node2, node3Создаём пробные файлы/папки в каталоге /mnt/ocfs2clst на одном из узлов и проверяем, что они видны на остальных узлах кластера OCFS2.
Размонтируем ФС на каждом узле:
root# umount /mnt/ocfs2clst
++ Расширение ФС OCFS2
Если потребуется увеличить размер хранилища:
*** Увеличиваем размер тома на СХД
*** Пересканируем том на сервере или перезагружаем узлы кластера
*** Расширяем ФСroot# tunefs.ocfs2 -S /dev/vdb
++ Добавление узла в кластер OCFS2
Если потребуется добавить ещё узел (например, node4, с ip 192.168.1.14) в кластер OCFS2, то необходимо выполнить команду на каждом узле:
root# o2cb_ctl -C -i -n node4 -t node -a number=4 -a ip_address=192.168.1.14 -a ip_port=7777 -a cluster=ocfs2clst
Необходимо заметить, что для обеспечения кворума, количество узлов должно быть нечётным.
++ Установка PostgreSQL
Устанавливаем пакеты на все узлы кластера:
root# apt install postgresql
Отключаем службу на каждом узле кластера, т.к. запуском СУБД будет управлять Pacemaker
root# systemctl disable postgresql
++ Настройка Pacemaker/Corosync
++ Установка пакетов
root# apt install pacemaker corosync crmsh fence-agents
++ Настройка Corosync
Служба Corosync обеспечивает обмен сообщениями между узлами кластера, с помощью неё отслеживается, что узлы работают корректно. А уже на основании информации о том какие узлы доступны, служба Pacemaker принимает решение о запуске сервисов (запуск виртуальных ip-адресов, монтирование файловых систем, запуск процессов СУБД).
Настройки Corosync хранятся в файле /etc/corosync/corosync.conf.
Рабочий пример файла указан ниже:
# Please read the corosync.conf.5 manual page
totem {
version: 2
cluster_name: pgclst
crypto_cipher: aes256
crypto_hash: sha256
}
logging {
fileline: off
to_stderr: yes
to_logfile: yes
logfile: /var/log/corosync/corosync.log
to_syslog: yes
debug: off
logger_subsys {
subsys: QUORUM
debug: off
}
}
quorum {
provider: corosync_votequorum
}
nodelist {
node {
name: node1
nodeid: 1
ring0_addr: 192.168.1.11
}
node {
name: node2
nodeid: 2
ring0_addr: 192.168.1.12
}
node {
name: node3
nodeid: 3
ring0_addr: 192.168.1.13
}
}++ Включение шифрования сообщений Corosync
Для повышения безопасности можно включить шифрование служебных сообщений при обмене между узлами кластера. Для этого на одном из узлов необходимо выполнить команду:
root# corosync-keygen
Она создаст файл /etc/corosync/authkey, этот файл необходимо скопировать на другие узлы кластера.
root@node1:~# scp /etc/corosync/authkey root@node2:/etc/corosync/authkey
root@node1:~# scp /etc/corosync/authkey root@node3:/etc/corosync/authkeyВ файле настроек /etc/corosync/corosync.conf необходимо задать параметры crypto_cipher и crypto_hash в секции totem:
totem {
...
crypto_cipher: aes256
crypto_hash: sha256
...
}Если вам необходимо разместить файл-ключ по не стандартному пути, то расположение можно указать с помощью директивы keyfile.
После изменений необходимо перезапустить службы на каждом узле:
root# systemctl restart corosync pacemaker
++ Параметры узлов кластера Corosync
Для работы кластера необходимо указать список узлов. Это делается в секции nodelist.
nodelist {
node {
name: node1
nodeid: 1
ring0_addr: 192.168.1.11
}
node {
name: node2
nodeid: 2
ring0_addr: 192.168.1.12
}
node {
name: node3
nodeid: 3
ring0_addr: 192.168.1.13
}
}После настройки, копируем файл /etc/corosync/corosync.conf на остальные узлы. Перезагружаем все узлы кластера и проверяем работу службы corosync с помощью команд corosync-quorumtool и crm_mon
root@node1:~# corosync-quorumtool -s
Quorum information
------------------
Date: Thu Jul 14 21:09:17 2022
Quorum provider: corosync_votequorum
Nodes: 3
Node ID: 1
Ring ID: 1.139
Quorate: Yes
Votequorum information
----------------------
Expected votes: 3
Highest expected: 3
Total votes: 3
Quorum: 2
Flags: Quorate
Membership information
----------------------
Nodeid Votes Name
1 1 node1 (local)
2 1 node2
3 1 node3
root@node1:~# crm_mon -1
Cluster Summary:
* Stack: corosync
* Current DC: node3 (version 2.0.5-ba59be7122) - partition with quorum
* Last updated: Thu Jul 14 21:11:18 2022
* Last change: Thu Jul 14 20:24:25 2022 by root via cibadmin on node1
* 3 nodes configured
* 0 resource instances configured
Node List:
* Online: [ node1 node2 node3 ]++ Настройка Pacemaker
Ресурсы Pacemaker описываются через XML-файлы, я вместо ручного написания xml-объектов буду использовать crm (CRM shell), где параметры ресурсов можно задать в виде аргументов.
++ Смена имени кластера
Ранее мы создали кластер OCFS2 с именем ocfs2clst, кластер Corosync с именем pgclst, теперь укажем имя кластера Pacemaker.
После установки, имя кластера Pacemaker, обычно debian, поменяем его также на pgclst:
root# crm_attribute --query --name=cluster-name
scope=crm_config name=cluster-name value=debian
root# crm_attribute --type crm_config --name cluster-name --update pgclst++ Параметры по-умолчанию
Меняем параметры по-умолчанию для новых ресурсов:
*** resource-stickiness - "липучесть" ресурса к текущему расположению в кластере (по-умолчанию 0), или "стоимость" переноса ресурса на другой узел. При увеличении значения, pacemaker будет стараться восстановить состояние сбойного ресурса на том же узле, при малом значении - предпочтёт восстановить ресурс запуском на других узлах.
root# crm_attribute --type rsc_defaults --name resource-stickiness --update 10
*** migration-threshold - кол-во сбоев ресурса на узле, при превышении которого происходит миграция на другой узел
root# crm_attribute --type rsc_defaults --name migration-threshold --update 2
++ Ассиметричный кластер
Можно указать, что для запуска каких-либо ресурсов необходимо наличие явного разрешающего правила. Это может понадобиться если не все узлы кластера идентичны по характеристикам:
root# crm_attribute -n symmetric-cluster -v false
После включения для каждого ресурса будет необходимо создать правила.
crm conf location <имя правила> <имя ресурса> <приоритет>: <узел>
Например, для ресурса виртуального ip-адреса (ip-pgclst) можно указать, что c приоритетом 100 он будет размещаться на узле node1, с приоритетом 10 - на узле node2, а на узле node3 его запуск будет запрещён (приоритет -infinity ):
root~# crm conf
crm(live)configure# location loc-ip-1 ip-pgclst 100: node1
crm(live)configure# location loc-ip-2 ip-pgclst 10: node2
crm(live)configure# location loc-ip-3 ip-pgclst -inf: node3++ Изоляция узлов (stonith)
В Pacemaker для каждого узла необходимо указать метод изоляции (fencing) в случае сбоя сетевой доступности. Осуществляется изоляция с помощью stonith ресурсов. Это могут быть программы для отключения питания на UPS, программы, которые подключаются к гипервизору и принудительно завершают работу виртуальной машины (нашего узла кластера) и много других вариантов.
Без STONITH устройств Pacemaker откажется запускать ресурсы:
root:~# crm_verify -L -V
(unpack_resources) error: Resource start-up disabled since no STONITH resources have been defined
(unpack_resources) error: Either configure some or disable STONITH with the stonith-enabled option
(unpack_resources) error: NOTE: Clusters with shared data need STONITH to ensure data integrity
Errors found during check: config not validСписок устройств для изоляции можно узнать из команды:
root# stonith_admin --list-installed
Параметры, необходимые устройству для работы, можно узнать:
root# stonith -t <имя устройста stonith> -n
Простейшие stonith ресурсы можно создать так.
Ресурс-пустышка dummy - ничего не отключает:
root# crm conf primitive sh-dummy stonith:null params hostlist="192.168.1.11 192.168.1.12 192.168.1.13"
root# crm conf clone fency sh-dummySSH-stonith - пытается подключиться к сбойному узлу через SSH и запланировать выключение через службу at (должна быть установлена на всех узлах).
root# apt install at
root# crm conf primitive fence-ssh stonith:ssh params hostlist="192.168.1.11 192.168.1.12 192.168.1.13"
root# crm conf clone fency fence-sshИмитируем сбой на узле node3:
root# stonith -t ssh -p "node1 node2 node3" -T reset node3
Для тестирования может понадобится отключение STONITH (НЕ РЕКОМЕНДУЕТСЯ):
root~# crm_attribute -n stonith-enabled -v false
Очистить ошибки можно командой:
root# stonith_admin --cleanup --history=node3
Стоит заметить что, в случае сбоя сети, кроме STONITH устройств, узел кластера может перезагрузить служба OCFS2.
Если у какого-либо узла пропадёт связь с другими узлами, но он продолжит посылать heartbeat сообщения на кластерный диск, то через 30 секунд (значение sysctl kernel.panic = 30) этот узел будет перезагружен принудительно.
++ Настройка PostgreSQL для работы под управлением Pacemaker/Corosync
Для запуска PostgreSQL необходимо создать три ресурса:
*** Ресурс, который будет монтировать ФС, где расположена БД
*** Ресурс виртуального ip-адреса, по которому будут обращаться клиенты к СУБД
*** Ресурс, запускающий процессы СУБД PostgreSQLПосле необходимо настроить правила совместного расположения ресурсов и указать порядок запуска.
В примере будет созданы ресурсы, обеспечивающие работу экземпляра СУБД.
++ Ресурс, обеспечивающий монтирование ФС с БД
++ Описание ресурса Pacemaker для ФС OCFS2
Ресурс fs-ocfs2 будет монтировать кластерную ФС OCFS2 в каталог /mnt/ocfs2clst на каждом узле.
Монтирование будет производится по метке ФС.
Том, где расположена БД, у меня имеет UUID метку ce92b1e7-30cb-4883-9a92-57c986f76acd (см. Создание ФС OCFS2).
root~# mkdir -p /mnt/ocfs2clst # выполнить на каждом узле
root@node1:~# crm conf
crm(live/node1)configure# primitive fs-ocfs2 Filesystem \
params device="/dev/disk/by-uuid/ce92b1e7-30cb-4883-9a92-57c986f76acd" \
directory="/mnt/ocfs2clst" \
fstype=ocfs2 options="rw,relatime,commit=5,coherency=buffered" \
op start timeout=60s interval=0 \
op stop timeout=60s interval=0 \
op monitor timeout=40 interval=20Полный список параметров монтирования можно узнать на странице https://www.kernel.org/doc/html/latest/filesystems/ocfs2.html
По-умолчанию, ресурс запускается только на одном узле, но так как у нас ФС кластерная, необходимо запустить ресурс на всех узлах.
Это возможно с помощью клона ресурса:
crm(live/node1)configure# clone fs-clone-ocfs2 fs-ocfs2
Проверяем конфигурацию и выходим:
crm(live/node1)configure# verify
crm(live/node1)configure# commit
crm(live/node1)configure# quitПосле создания ресурса, ФС должна автоматически смонтироваться на всех узлах кластера.
root@node1:~# mounted.ocfs2 -f
Device Stack Cluster F Nodes
/dev/vdb o2cb ocfs2clst node1, node3, node2++ Правила размещения ресурса на узлах
Если указан параметр symmetric-cluster=false, то для запуска ресурсов необходимо указать явные правила, где ресурсы могут запускаться. Указываем, что ресурс кластерной ФС должен запускаться на всех узлах кластера с равным приоритетом 1:
root~# crm conf
crm(live)configure# location loc-fs-ocfs2-1 fs-clone-ocfs2 1: node1
crm(live)configure# location loc-fs-ocfs2-2 fs-clone-ocfs2 1: node2
crm(live)configure# location loc-fs-ocfs2-3 fs-clone-ocfs2 1: node3
crm(live)configure# verify
crm(live)configure# commit
crm(live)configure# quitЕсли symmetric-cluster=true (или параметр не задан), то создавать правила не обязательно.
++ Ресурс виртуального ip-адреса
Создаём ресурс ip-pgclst виртуального ip-адреса 192.168.1.10. Именно этот ip-адрес будет использовать СУБД для приёма подключений.
root~# crm conf
crm(live)configure# primitive ip-pgclst IPaddr \
params ip=192.168.1.10 \
op monitor interval=10sЕсли в атрибутах кластера Pacemaker указан параметр symmetric-cluster=false, то аналогично ресурсу файловой системы создаём правила размещения. Ресурс ip-адреса будет располагаться совместно с СУБД. Если производительность узлов отличается, то можно указать разные приоритеты для запуска. Предположим, что node1 мощнее, чем node2, а node3 вообще исключим для работы СУБД:
root~# crm conf
crm(live)configure# location loc-ip-pgclst-1 ip-pgclst 100: node1
crm(live)configure# location loc-ip-pgclst-2 ip-pgclst 10: node2
crm(live)configure# location loc-ip-pgclst-3 ip-pgclst -inf: node3
crm(live)configure# verify
crm(live)configure# commit
crm(live)configure# quitЕсли symmetric-cluster=true (или параметр не задан), то создавать правила не обязательно.
У меня в примере правила размещения не используются.
++ Ресурс Pacemaker, запускающий процессы СУБД PostgreSQL
++ Инициализация файлов кластера БД PostgreSQL
Изменяем владельца и права доступа на каталог с БД:
root# chown -R postgres:postgres /mnt/ocfs2clst
root# chmod 750 /mnt/ocfs2clstИнициализируем файлы кластера БД PostgreSQL в каталоге /mnt/ocfs2clst/pg-data с включением контроля чётности страниц БД, а после запускаем СУБД:
postgres@node1:~$ /usr/lib/postgresql/13/bin/initdb -D /mnt/ocfs2clst/pg-data/ -A peer -k
postgres@node1:~$ /usr/lib/postgresql/13/bin/pg_ctl -D /mnt/ocfs2clst/pg-data/ start++ Настройка конфигурации PostgreSQL
Подключаемся к СУБД через unix-сокет:
root@node1:~# su - postgres
postgres@node1:~$ psqlИзменяем параметры БД для возможности работы под управлением Pacemaker:
psql> alter system set logging_collector=on;
psql> alter system lc_messages = 'C.UTF-8';
psql> alter system set listen_addresses='192.168.1.10';Здесь я включил сборщик сообщений (logging collector), поменял язык сообщений на английский (при работе по Pacemaker, русские сообщения заменялись вопросами) и указал, что СУБД должна принимать соединения только на кластерном ip-адресе.
Если потребуется в кластере Pacemaker запустить несколько экземпляров Postgresql, то необходимо разместить unix-сокет СУБД по отдельным каталогам, так как по-умолчанию все экземпляры будут создавать сокет в каталоге /tmp.
psql> alter system set unix_socket_directories = '/mnt/ocfs2clst/pg-data';
Например, если бы у нас было две БД:
СУБД 1, кластерный ip 192.168.1.21, каталог /mnt/ocfs2clst/pg-db1
СУБД 2, кластерный ip 192.168.1.22, каталог /mnt/ocfs2clst/pg-db2то unix_socket_directories необходимо задать:
psql db1> alter system set unix_socket_directories = '/mnt/ocfs2clst/pg-db1';
psql db2> alter system set unix_socket_directories = '/mnt/ocfs2clst/pg-db2;В дальнейшем для подключения через unix-сокет необходимо указать путь к нему (команду необходимо выполнять на том узле, где работает СУБД):
postgres@node1:~$ psql -h /mnt/ocfs2clst/pg-data/
Редактируем файл /mnt/ocfs2clst/pg-data/pg_hba.conf, разрешаем подключение по сети с паролем:
...
# IPv4 network connections
host all all all md5
...После внесения настроек, останавливаем СУБД:
postgres@node1:~$ /usr/lib/postgresql/13/bin/pg_ctl -D /mnt/ocfs2clst/pg-data/ stop
++ Создание ресурса СУБД PostgreSQL
root~# crm configure
crm(live/node1)configure# primitive db-pgclst pgsql \
params pgctl="/usr/lib/postgresql/13/bin/pg_ctl" \
psql="/usr/lib/postgresql/13/bin/psql" \
pgdba=postgres \
pglibs="/usr/lib/postgresql/13/lib" \
pgdata="/mnt/ocfs2clst/pg-data" \
socketdir="/mnt/ocfs2clst/pg-data" \
config="/mnt/ocfs2clst/pg-data/postgresql.conf" \
op start timeout=120s interval=0 \
op stop timeout=120s interval=0 \
op monitor timeout=30 interval=30Значения параметра socketdir в описании ресурса Pacemaker должно совпадать с параметром unix_socket_directories в файле конфигурации PostgreSQL postgresql.conf/postgresql.auto.conf.
++ Правила размещения ресурса на узлах
Аналогично ресурсу ip-адреса, если в атрибутах указан параметр symmetric-cluster=false, то создаём правила размещения ресура:
root~# crm conf
crm(live)configure# location loc-db-pgclst-1 db-pgclst 100: node1
crm(live)configure# location loc-db-pgclst-2 db-pgclst 10: node2
crm(live)configure# location loc-db-pgclst-3 db-pgclst -inf: node3
crm(live)configure# verify
crm(live)configure# commit
crm(live)configure# quitЕсли symmetric-cluster=true (или параметр не задан), то создавать правила не обязательно, тогда СУБД сможет запускаться на любом из узлов, при условии, что ресурсу ip-адреса так же разрешен запуск на всех узлах.
У меня в примере правила размещения не используются.
++ Правила, описывающие совместное расположение ресурсов
Необходимо, чтобы виртуальный ip-адрес и экземпляра СУБД PostgreSQL располагались на одном узле, иначе СУБД не запустится.
crm conf colocation <имя правила> <приоритет>: <ресурс1> <ресурс2>
Для этого создаём соответствующее правило:
root~# crm conf
crm(live/node1)configure# colocation col-ip-pgsql inf: ip-pgclst db-pgclst
crm(live/node1)configure# verify
crm(live/node1)configure# commit
crm(live/node1)configure# quit++ Правила, описывающие порядок запуска ресурсов
Необходимо, чтобы ресурс виртуального ip-адреса и ресурс, монтирующий кластерную ФС OCFS2, запускались раньше ресурса СУБД PostgreSQL.
crm conf order <имя правила> <приоритет>: <ресурс1> <ресурс2>
Для этого создаём соответсвующие правила:
root~# crm conf
crm(live/node1)configure# order ord-fs-pgsql Mandatory: fs-clone-ocfs2 db-pgclst
crm(live/node1)configure# order ord-ip-pgsql Mandatory: ip-pgclst db-pgclst
crm(live/node1)configure# verify
crm(live/node1)configure# commit
crm(live/node1)configure# quit++ Проверка работы
После настройки ресурсов проверяем, что все они запущены с помощью команды crm_mon:
root@node1:~# crm_mon -nr1
Cluster Summary:
* Stack: corosync
* Current DC: node3 (version 2.0.5-ba59be7122) - partition with quorum
* Last updated: Sat Jul 16 18:04:00 2022
* Last change: Sat Jul 16 10:52:30 2022 by root via cibadmin on node2
* 3 nodes configured
* 8 resource instances configured
Node List:
* Node node1: online:
* Resources:
* fs-ocfs2 (ocf::heartbeat:Filesystem): Started
* sh-dummy (stonith:null): Started
* Node node2: online:
* Resources:
* sh-dummy (stonith:null): Started
* fs-ocfs2 (ocf::heartbeat:Filesystem): Started
* db-pgclst (ocf::heartbeat:pgsql): Started
* ip-pgclst (ocf::heartbeat:IPaddr): Started
* Node node3: online:
* Resources:
* sh-dummy (stonith:null): Started
* fs-ocfs2 (ocf::heartbeat:Filesystem): Started
Inactive Resources:
* No inactive resourcesИз вывода видно, что СУБД запущена на узле node2. Подключимся к нему через ssh и создадим пользователя в Postgresql:
user@pc:~$ ssh user@192.168.1.12
user@node2:~$ sudo su - postgres
postgres@node2:~$ psql -h /mnt/ocfs2clst/pg-data/
postgres=# create role pguser login encrypted password 'пароль';
postgres=# \qПроверяем подключение к СУБД с клиента:
user@pc:~$ psql -h 192.168.1.10 -U pguser postgres
postgres=> select count(*) from pg_settings;
count
-------
308
(1 строка)С любого узла кластера перемещаем СУБД на другой узел:
root@node1:~# crm_resource --move -r db-pgclst -H node1
или с помощью CRM Shell
root@node1:~# crm resource move db-pgclst node1
Определяем где запущен ресурс:
root@node1:~# crm_resource -W -r db-pgclst
resource db-pgclst is running on: node1Выполняем повторный запрос с клиента:
postgres=> select count(*) from pg_settings;
FATAL: terminating connection due to administrator command
сервер неожиданно закрыл соединение
Скорее всего сервер прекратил работу из-за сбоя
до или в процессе выполнения запроса.
Подключение к серверу потеряно. Попытка восстановления удачна.
psql (14.1, сервер 13.7 (Debian 13.7-0+deb11u1))
postgres=> select count(*) from pg_settings;
count
-------
308
(1 строка)Как видно, при перемещении ресурса все соединения с СУБД закрылись, но повторный sql-запрос выполнился успешно.
Команды перемещения ресуров crm_resource --move или crm resource move на самом делее создают в базе Pacemaker CIB запись:
<rsc_location id="cli-prefer-db-pgclst" rsc="db-pgclst" role="Started" node="node1" score="INFINITY"/>
Эта запись указывает в дальнейшем запускать ресурс db-pgclst на узле node1. Для того чтобы вернуть возможность запуска ресурса на любом из узлов достаточно выполнить одну из команд:
root# crm_resource -r db-pgclst --clear
root# crm resource clear db-pgclst++ Команды управления кластером Pacemaker
root# crm_verify -L -V - проверка конфигурации Pacemaker
root# crm_mon -rf - отслеживание статуса ресурсов
root# crm_resource -W -r db-pgclst - определить расположение ресурса db-pgclst в кластере
root# crm node standby - приостановить работу узла
root# crm node online - возобновить работу узла
root# crm resource status - посмотреть список ресурсов
root# crm resource move db-pgclst node2 - мигрировать ресурс ip-pgclst на узел node2
root# crm resource clear db-pgclst - убрать привязку после переноса
root# crm resource stop db-pgclst - остановить ресурс db-pgclst
root# crm resource start db-pgclst - запустить работу ресурса db-pgclst
root# crm resource cleanup db-pgclst или # crm_resource --resource db-pgclst --cleanup - сброс количества ошибок ресурса
root# crm configure delete db-pgclst - удаление ресурса
root# cibadmin --query > tmp.xml - создать дамп базы Pacemaker CIB
URL:
Обсуждается: http://www.opennet.me/tips/info/3211.shtml
Тот момент когда вместо типовых решений используют лютый костылинг, после чего имея кучу анального с... Са.
С удовольствием прочитаю Вашу статью как правильно делать. Когда ждать?
Определили бы задачу вначале чего хотите
Если просто master-master то вам https://www.percona.com/blog/2020/06/09/multi-master-replica.../
Если поиграться с пцмаркерами, бекапами и неработающими БД то пожалуйте инструкции из статьи, а еще совет сразу для пущего эффекта в докер-кубер это завернуть
> Определили бы задачу вначале чего хотите
> Если просто master-master то вам https://www.percona.com/blog/2020/06/09/multi-master-replica.../
> Если поиграться с пцмаркерами, бекапами и неработающими БД то пожалуйте инструкции из
> статьи, а еще совет сразу для пущего эффекта в докер-кубер это
> завернутьОлег,
Я ничего не имею против критики, статей на английском языке и конкретно Вас.
Но мой вопрос был в том, чтобы Вы показали свою статью на русском языке, если уж критикуете.
Я в таких случаях либо в частной беседе предлагаю свои правки автору, либо ссылаюсь на то что делал сам.
Из моей практики тот костылинг, что предлагает автор статьи, приводит к непонятным последствиям.Из моего жизненного опыта, мы живём не в 90х, чтобы придерживаться ещё старомодной этики, которая приводит к ошибкам в реализация уже серьёзных задач.
Я привёл стандартные механизмы мультимастера, автор же реализует схему, о которой разработчики посгрес даже не догадываются, т.е этот путь костылинг с нарушением логики работы посгрес в целом, при том костылинг не имеющий под собой никакого зерна оправдания внедрения, ибо он многократно сложнее стандартных механизмов
В статье описывается не multi master, в примере выше СУБД работает только на одном узле, при сбое процессов/железа автоматически переезжает на рабочий узел. Это open source аналог oracle rac one node.
И кеши посгрес в курсе этого?
> И кеши посгрес в курсе этого?Если упал сервер, то там никаких кешей уже нет.
Pacemaker запускает процесс postgres на одном из оставшихся рабочих узлов, СУБД определяет момент последней контрольной точки и применяет необходимые wal логи.
Всё, что было в кешах СУБД, но не попало в файлы БД, восстанавливается через wal.
> И кеши посгрес в курсе этого?Ну какие ещё "кэши"? clog при каждом chekpoint-е в файлы сбрасывается. А больше ничего для из памяти для восстановления после сбоя и не нужно. Один экземпляр потух. Другой поднялся, смонтировал кластер и запустил стандартный recovery. Это решение плохо тем, что этот самый recovery нужен. А для Слона типично, что на нагруженном проме время между очередными checkpoint-ами имеет смысл накручивать насколько позволяет пространство под wal. Т.е. рекавери будет идти тупо долго.
Абсолютно да.
Причём этот костылинг чреват в случаях развала сети, а не падения ноды.
> Я привёл стандартные механизмы мультимастераДа, забавно. Из перечисленного более-менее потребен только BDR, но он платный. И, опять же, его внедрение происходит поверх repmgr или всё того же писмэйкера.
Олег, а вы сами какое угодно master-master-решение внедряли/эксплуатировали, пусть и не на Слоне, а?
Ocfs2 лучше монтировать с опцией coherency=full - так медленнее, но надёжнее.
> Ocfs2 лучше монтировать с опцией coherency=full - так медленнее, но надёжнее.coherency=full так-то дефолт
Для файлов active-standby, а особенно DBMS - всё правильно, coherency full проложит мелкую запись в лог в разы.
(это конечно если у нас direct IO для лога подразумевается)
the same thing can be done using postgres streaming replication, without shared FS. there is pacemaker postgres resource, that can take care about node promotion from slave to master. I did it for 3 nodes cluster - 1 active 2 stand-by for zabbix db with timescaledb extension, DB size was close to 2Tb.
> the same thing can be done using postgres streaming replication, without shared
> FS. there is pacemaker postgres resource, that can take care about
> node promotion from slave to master. I did it for 3
> nodes cluster - 1 active 2 stand-by for zabbix db with
> timescaledb extension, DB size was close to 2Tb.Streaming repl needs two time more space.
Садо-мазо. По набору компонент.
"Под нагрузкой данное решение не проверялось" - т.е. теория ради теории.
- Коросинк развалится там, где возможны непредсказуемые делеи, т.е. решение для двух соседних стоек ДЦ
- Pacemaker требует STONITH, а реальный STONITH ныне - это очень редкая вещь. Всякие псевдо-варианты на уровне тушения виртуалок встанут колом, как только развалится менеджовая сеть, и когда это всё соберётся взад (скорее всего с раздельным написанием первой буквы) - результат непредсказуем, т.е. опять же максимум годно для полутора стоек в одном ДЦ
- Из реально работающего cross-DC здесь OCFS2, но её тоже надо уметь готовить - никаких коросинков с пацемакерами, внутренний кластерный стек там достаточно вылизанный, при этом общее дисковое хранилище в качестве дополнительного арбитра работает железноВ итоге не проще ли взять MySQL с асинхронной репликацией и не извращаться?
В худшем случае - зайдёт Galera с синхронным коммитом.
> - Коросинк развалится там, где возможны непредсказуемые делеи, т.е. решение для двух
> соседних стоек ДЦВы удивитесь, но сбой этот как раз и есть случай "непредсказуемого делея". Подобные схемы и нужны, чтобы в случае "непредсказуемого делея" поднять новый мастер.
> - Pacemaker требует STONITH
Любые схемы с транзакциями требуют STONITH.
> В итоге не проще ли взять MySQL с асинхронной репликацией и не
> извращаться?
> В худшем случае - зайдёт Galera с синхронным коммитом.Если данные не важны и модель данных уровня какого-нибудь web-проекта, где данные и время ничего не стоят, да.
- Любые схемы с транзакциями требуют STONITH.
Нет.- Если данные не важны и модель данных уровня какого-нибудь web-проекта, где данные и время ничего не стоят, да.
Надувание щёк не предмет для обсуждения однозначно. И да, возможно тут просто незнание место быть имеет. Потому что репликация в MySQL - это не репликация в постхрюках.
> - Любые схемы с транзакциями требуют STONITH.
> Нет.Было бы интересно почитать что-нибудь о том, как обходиться без STONITH.
Стандартный нечётный арбитраж с самоустранением (остановкой операций, не обязательно полностью, можно до момента восстановления кворума) нодами, не имеющими кворума. Надёжнее - с дополнительным посредником арбитража, который расположен не на нодах и не на стыках между ними, при правильной конфигурации становится возможен вторичный кворум, и количество нод вполне может быть и чётным без особых последствий, главное, чтобы не было локационного сплита 1/2. Единственным существенным моментом при этом является необходимость предварительной блокировки операций записи, чтобы не дать провести запись в случае потери кворума.
> Стандартный нечётный арбитраж с самоустранением (остановкой операций, не обязательно
> полностью, можно до момента восстановления кворума) нодами, не имеющими кворума. Надёжнее
> - с дополнительным посредником арбитража, который расположен не на нодах и
> не на стыках между ними, при правильной конфигурации становится возможен вторичный
> кворум, и количество нод вполне может быть и чётным без особых
> последствий, главное, чтобы не было локационного сплита 1/2. Единственным существенным
> моментом при этом является необходимость предварительной блокировки операций записи,
> чтобы не дать провести запись в случае потери кворума.Ну а зачем? В чём профит? Относительно простого пристрелить. "Нечёткий арбитраж" -- простите, ржал. Вы на "нечёткий арбитраж" в типично сложных случаях потратите астрономически больше времени, чем просто всё вырубить. И, снова, возращаемся к адекватности угадывания. А угадывание -- всегда угадывание. Но одно дело угадывать как лучше что-то сделать, не теряя ничего, кроме времени, чем угадывать: потерять даные... или не потерять. Причём, ладно бы был выбор, -- потерять немножко данных, но выиграть во времени исполнения -- но нет же -- вы предлагает потерять неизвестно сколько времени взамен на потерять... неизвестно сколько данных )))) Хреновый выбор.
Эээээ, а можно как-то по буквам читать что-ли.
Нечётный, а не нечёткий. 2N+1
> Эээээ, а можно как-то по буквам читать что-ли.
> Нечётный, а не нечёткий. 2N+1Ааа ) Ну бывает, слепой уже. Так работают патрони и repmgr. Они оркеструют репликацию узлов Слона. Писмэйкер и коросинком может и там пригодиться. Всё таки это крайне универсальные, хотя, в общем-то, и крайне затратные и сложные инструменты.
> Потому что репликация в MySQL - это не репликация в постхрюках.А что не так с репликацией в Слоне?
Можно односложно?Всё.
А при чём тут репликация? Описанное решение как раз без репликации. Репликация подразумевает, что у вас есть н-узлов, данные на которых идентичны (строго или "в конце концов"). Т.е. каждый узел с экземпляром обладает своей репликой данных, с которой и работает. Тут же, как я понял, узлы с экземпляром используют одни и те же данные, доступ к которым разделён по времени.
Вопрос был про репликацию, безотносительно.
А как-то более предметно? В Слоне репликация работает. Она надёжно наблюдаема. И крайне легка в настройке. Что из этого вы способны аргументировано оспорить?
И даже в изменения схемы уже умеет?
Не понял вас, не понял, что значит "в изменение схемы". Понятие схемы очень уж многозначное. Можете как-то пояснить о чём речь в данном случае, если будет время?
Вы же не о схеме в БД, которая пространство имён, я так понимаю, так?
Есть механизм "логической репликации", в которой издателю нет никакого дела до того, что там получатель на своей стороне с данными делает и как, лишь бы получатель подтверждение присылал. Это не достаточно?
Ну и да, поскольку у нас тут простой active-standby - можно тупо обойтись keepalived и монтированием разделяемого раздела на той ноде, которая должна живой стать, даже с OCFS2 не извращаясь.
> Садо-мазо. По набору компонент.
> "Под нагрузкой данное решение не проверялось" - т.е. теория ради теории.Набор компонентов один из наиболее тиражных. Большая часть отказоустойчивых кластеров со Слоном реализованы либо на стеке коросинка с писмэйкером, либо на repmrg. Чуть меньше на патрони. При этом именно коросинк с писмэйкером позволяют реализовать сколь угодно сложные и изощрённые решения. Если не стоит задача делать master-master.
> Большая часть отказоустойчивых кластеров со Слоном реализованы либо на стеке коросинка с писмэйкером, либоВот именно поэтому я ко всему этому счастью (постхрюку) близко не подхожу.
Сколь угодно сложные и изощрённые решения позволяет MySQL и его вариации. ВПЛОТЬ до master-master.
Без всяких коросинков. Или с ними, если хочется извращаться.Что же до задачи - на коросинках кросс-дц с парой ms делеев уже проблема.
Про MySQL ничего сказать не могу. Мой опыт в пользу того, чтобы MySQL не применять ни для чего сложнее регистратора событий.
И нет, для MySQL нет и близко решений master-master такого уровня, которые есть для Слона.
Похоже на одноузловой РЭК. Общий кластер БД. Экземпляры монтируют его в разное время. Вполне жизненно.
Не совсем понятно на фига в этой схеме коросинк и прочее.
Обычного keepalived и ocfs2 с арбитрацией на разделяемой хранилке будет более, чем достаточно.
(причём с арбитрацией на хранилке даже в конфигурации с двумя нодами будет работать, если нужен здоровый минимализм)
Писмэйкер и коросинком позволяют сделать стэк отказа сколь угодно глубоким. Можно в этот пирог запихнуть реакцию на что угодно, хоть на фазу луны, если это нужно. Другое дело, нужно ли. Но другой вопрос.
Писмэйкер и коросинком позволяют сделать проникновение граблей сколь угодно глубокимFixed.
> Писмэйкер и коросинком позволяют сделать проникновение граблей сколь угодно глубокимНу и это тоже. Это тёмная сторона гибкости и функциональности.
Есть же patroni, его проще поднять и это решение работает, проверено:
https://github.com/zalando/patroni
А какой смысл в кластерной файловой системе? Сэкономить 50% места и в результате получить рост латенси (читай IOPS) в 100 раз из-за сети? Или сколько у вас получилось если учитывать что базовый сервер с SSD.
В случае с обычной master-slave репликацией и тулзой сбоку переключающей мастера (patroni, stolon, repmgr и т.д.) с реплик еще и читать можно (большинству типовых запросов типовых приложений не важна консистентность) получая производительность х3.
Если суммировать все потери то статья про то как на ровном месте сделать постгрес в 10 раз медленнее, а конфигурацию запутанее.