Skip to content

Использование Patroni для создания кластера высокой доступности Postgres — Часть 2: Postgres и Patroni

Автор: Shaun Thomas, Using Patroni to Build a Highly Available Postgres Cluster—Part 2: Postgres and Patroni



Статьи серии:


Добро пожаловать во вторую часть нашей серии о создании высокодоступного кластера Postgres с помощью Patroni! Первая часть была полностью посвящена созданию DCS с использованием etcd, что обеспечило критически важный уровень, который Patroni использует для хранения метаданных и гарантии уникальности маркера лидерства во всём кластере.


Имея этот прочный фундамент, пришло время построить следующий уровень нашего стека: сам Patroni. Patroni выполняет работу по управлению службой Postgres и предоставляет интерфейс командной строки для администрирования и мониторинга узлов. Технически кластер Patroni будет завершён в конце этой статьи, но оставайтесь с нами до третьей части, где мы добавим уровень маршрутизации, который объединит всё воедино.


Надеюсь, у вас всё ещё есть три виртуальные машины, на которых вы установили etcd. Они будут тем местом, где произойдёт всё остальное, так что если вы ещё не прошли шаги из первой части, вернитесь, когда будете готовы.


В противном случае, давайте начнём!



Установка Postgres


На сайте сообщества Postgres есть невероятно подробная страница, посвящённая установке на различных платформах. Для удобства это руководство включает упрощённую версию инструкций для Debian. Выполните эти шаги на всех трёх серверах.


Начните с настройки репозитория PGDG:



sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh


Затем установите предпочитаемую версию Postgres. Для целей этого руководства мы также остановим Postgres и удалим начальный кластер, который создаёт пакет Postgres. Patroni в любом случае всё это воссоздаст, и он должен управлять этим.



sudo apt install -y postgresql-18
sudo systemctl stop postgresql@18-main
sudo pg_dropcluster 18 main


Также важно полностью отключить стандартную службу Postgres, поскольку управление будет осуществляться Patroni:



sudo systemctl disable postgresql


Наконец, установите версию Patroni, включённую в репозитории PGDG. Она должна быть доступна на поддерживаемых платформах, таких как Debian и RedHat, но если её нет, возможно, придётся прибегнуть к официальным инструкциям по установке.



sudo apt install -y patroni


После завершения этой команды у нас должно быть три чистые виртуальные машины, готовые к настройке.



Настройка Patroni простым способом


Пакет Patroni для Debian предоставляет инструмент pg_createconfig_patroni, который преобразует шаблон Patroni в файл конфигурации, настроенный специально для систем Debian. Прежде чем использовать его, необходимо изменить часть этого шаблона для использования etcd, так как ZooKeeper используется по умолчанию. Выполните эти шаги на всех трёх серверах.



cat<<EOF|sudo tee /etc/patroni/dcs.yml
etcd3:
host: 127.0.0.1:2379
EOF


Обратите внимание, что заголовок YAML показывает «etcd3», а не просто «etcd». Patroni использует etcd2 по умолчанию для обратной совместимости, а версия 3 требует гораздо более другого протокола связи.


Затем создайте остальную часть конфигурации с помощью одной команды:



sudo pg_createconfig_patroni 18 demo


Это создаёт файл с именем 18-demo.yml в каталоге конфигурации /etc/patroni, который systemd использует при управлении этим конкретным кластером. Нам также понадобится это для вызова patronictl.



Понимание конфигурации Patroni


Несмотря на то, что файл конфигурации уже готов, важно понять назначение каждого раздела и что он делает. Это позволит пользователям других платформ вручную настроить Patroni при необходимости.


Начнём с самого верхнего раздела, посвящённого DCS:



scope: "18-demo"
namespace: "/postgresql-common/"
name: patroni-demo-1

etcd3:
host: 127.0.0.1:2379


Когда Patroni пишет в DCS, все ключи начинаются с пути, указанного параметром namespace. Поскольку один DCS может обслуживать несколько кластеров, ключи для этого кластера должны включать scope в пути ключа. name указывает, как Patroni должен обращаться к этому конкретному узлу. Инструмент конфигурации на самом деле использует DCS, чтобы увидеть, какие имена уже зарезервированы, поэтому каждая ВМ будет уникально идентифицирована. Проверьте все три, чтобы убедиться, что они верны.


Следующий раздел, помеченный bootstrap, определяет, как Patroni должен создать начальный кластер Postgres, какие параметры использовать и другую важную информацию. Он довольно длинный, поэтому давайте рассмотрим каждую отдельную часть:



bootstrap:
method: pg_createcluster
pg_createcluster:
command: /usr/share/patroni/pg_createcluster_patroni


Обычно Patroni использует pg_init при создании нового кластера, но для полной совместимости с особенностями организации Debian в отношении Postgres конфигурация указывает альтернативную команду. Эта короткая секция, скорее всего, появится только в системе Debian.


Далее идёт раздел dcs в разделе bootstrap. Все эти параметры должны быть освещены в документации по динамическим настройкам, но мы объясним важные из них. Важно отметить, что любые настройки, определённые здесь, фактически сохраняются в слое DCS и применяются к Patroni на всех узлах. После инициализации единственный способ изменить эти параметры — через утилиту patronictl. Хорошо убедиться, что все они установлены правильно, так как изменение их позже несколько неудобно.



dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
check_timeline: true
primary_start_timeout: 300
synchronous_mode: false


Эти параметры определяют, как Patroni взаимодействует со слоем DCS и как он должен управлять определёнными функциями Postgres. Помните, что маркер лидерства определяет, какой узел является первичным, поэтому ttl определяет, как долго должна длиться эта аренда, loop_wait контролирует, как долго ждать между продлениями аренды, а retry_timeout указывает, как долго ждать ответа от DCS.


Мы включили primary_start_timeout в этот вывод, потому что гонка лидеров не совсем абсолютна. Если Patroni повышает узел до первичного или определяет, что Postgres вышел из строя, у него есть этот таймаут до того, как он принудительно выполнит переключение. Это обеспечивает период ожидания для завершения восстановления после сбоя, но вы можете обнаружить, что значение по умолчанию в пять минут слишком велико.


Ещё один важный параметр здесь — synchronous_mode, который указывает Patroni, что он должен управлять настройкой Postgres synchronous_standby_names, автоматически используя имена других узлов в кластере. Так вы можете включить синхронную репликацию в Patroni.


Далее следует раздел postgresql внутри dcs:



postgresql:
use_pg_rewind: true
remove_data_directory_on_rewind_failure: true
remove_data_directory_on_diverged_timelines: true
use_slots: true
parameters:
wal_level: hot_standby


Этот раздел определяет, как Patroni должен управлять службой Postgres. Первые несколько параметров управляют тем, как Patroni перерабатывает старые первичные узлы, например, используя утилиту pg_rewind когда это возможно, и следует ли удалять каталог данных в крайнем случае. Patroni также использует слоты репликации по умолчанию, чтобы предотвратить ненужную перестройку реплик в сценариях сбоев.


Вы также можете передавать настройки GUC непосредственно в Postgres на всех узлах через раздел parameters. Это полезно для предоставления важных обще кластерных настроек, которые могут не зависеть от оборудования, таких как wal_level, max_connections или hot_standby_feedback.



GUC — это аббревиатура от Grand Unified Configuration (Великая Единая Конфигурация).
Это термин, используемый в PostgreSQL для обозначения параметров конфигурации сервера. GUC — это механизм, который управляет настройками PostgreSQL: от того, сколько памяти выделяется под буферный кэш (shared_buffers), до того, как логируются сообщения (log_min_messages), или работает ли синхронная репликация (synchronous_commit).



Последний раздел под заголовком dcs.postgresql — это pg_hba:



pg_hba:
- local all all peer
- host all all 127.0.0.1/32 md5
- host all all ::1/128 md5
# - host all all 192.168.6.10/16 md5
- local replication all peer
- host replication all 127.0.0.1/32 md5
- host replication all ::1/128 md5
- host replication all 192.168.6.10/16 md5


Вы захотите настроить этот раздел перед запуском Patroni; он использует его для построения файла pg_hba.conf, который управляет доступом к входящим соединениям. По умолчанию будет разрешены соединения в подсети сервера, если вы раскомментируете отключённую строку, в противном случае доступ только локальный.


Далее идёт ещё один раздел postgresql, но это заголовок верхнего уровня, предназначенный для указания Patroni, как он должен обрабатывать Postgres на этом конкретном сервере. Эти разделы более подробно объясняются в документации по настройке YAML Patroni.


Этот пример начинается с некоторого контента, специфичного для Debian:



postgresql:
create_replica_method:
- pg_clonecluster
pg_clonecluster:
command: /usr/share/patroni/pg_clonecluster_patroni


Как и прежде, это сделано для того, чтобы Debian мог интегрироваться с другими пакетными инструментами Postgres, поэтому на других платформах это можно пропустить. После этого идёт несколько важных параметров для обработки соединений:



listen: "*:5432"
connect_address: 192.168.6.10:5432
use_unix_socket: true


Этот пример фактически указывает Patroni, как он должен подключаться к локальной службе Postgres для административных действий. Patroni использует unix-сокеты, когда это возможно, используя эти настройки, что имеет смысл, поскольку Patroni запускается от пользователя ОС postgres и имеет прямой доступ к сокету.


Затем идёт интересный раздел, который определяет несколько путей:



data_dir: /var/lib/postgresql/18/demo
bin_dir: /usr/lib/postgresql/18/bin
config_dir: /etc/postgresql/18/demo
pgpass: /var/lib/postgresql/18-demo.pgpass


Patroni знает, что он будет установлен в нескольких разных средах, где каталоги Postgres и конфигурации могут находиться в совершенно произвольных местах. Это значения по умолчанию для Postgres 18, работающего в системе Debian.


Наконец, есть второй раздел parameters, предназначенный для параметров, которые должны применяться только к этому конкретному серверу Postgres:



parameters:
unix_socket_directories: '/var/run/postgresql/'
logging_collector: 'on'
log_directory: '/var/log/postgresql'
log_filename: 'postgresql-18-demo.log'


Ничего здесь не должно быть удивительным; в основном это хранилище журналов для локального экземпляра и местонахождение каталога unix-сокетов. Вероятно, они будут одинаковыми для всего кластера, но безопаснее оставить их вне раздела DCS. Если когда-либо возникнут различия, вызванные миграцией оборудования или дистрибутива ОС, вы захотите иметь возможность изменять их локально.


В любом случае, найдите время, чтобы изучить файл /etc/patroni/18-demo.yml на каждом узле и проверить его на наличие ошибок.



Запуск и проверка Patroni


Пакет Patroni предоставляет стандартный файл службы systemd; просто включите и запустите службу на всех ВМ.



sudo systemctl enable patroni@18-demo
sudo systemctl start patroni@18-demo


Один из трёх узлов «выиграет» гонку лидеров и станет первичным для кластера. Затем Patroni вызывает команду pg_createcluster_patroni на этой системе, чтобы создать каталоги данных и конфигурации перед запуском Postgres. На других узлах Patroni вместо этого вызывает pg_clonecluster_patroni для создания новых потоковых реплик. Если вы хотите, чтобы конкретный узел запустился как первичный, просто запустите Patroni на этом узле и подождите, пока он создаст кластер, прежде чем запускать службу на двух других.


Конечным результатом на всех трёх системах должна быть новая база данных «demo», видимая для pg_lsclusters:



pg_lsclusters

Ver Cluster Port Status Owner Data directory Log file
18 demo 5432 online,patroni postgres /var/lib/postgresql/18/demo /var/log/postgresql/postgresql-18-demo.log


Следующий шаг — проверить статус самого кластера Patroni. Вы должны иметь возможность запустить эту команду с любого узла от пользователя ОС postgres. Она также будет работать от root, но теперь, когда Patroni установлен и управляет кластером, лучше избегать использования пользователя root.



patronictl -c /etc/patroni/18-demo.yml list


+ Cluster: 18-demo (7606465692216410488) -+-----------+----+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+----------------+--------------+---------+-----------+----+-------------+-----+------------+-----+
| patroni-demo-1 | 192.168.6.10 | Leader | running | 2 | | | | |
| patroni-demo-2 | 192.168.6.11 | Replica | streaming | 2 | 0/4000060 | 0 | 0/4000060 | 0 |
| patroni-demo-3 | 192.168.6.12 | Replica | streaming | 2 | 0/4000060 | 0 | 0/4000060 | 0 |
+----------------+--------------+---------+-----------+----+-------------+-----+------------+-----+


Этот вывод говорит нам, что кластер здоров и работает, узел 1 является текущим первичным, обе реплики потоковые, и нет задержки репликации. Успех!



Редактирование конфигурации кластера


Последний шаг, который может потребоваться, — это изменить конфигурацию кластера, хранящуюся в слое DCS. Это параметры Postgres и записи pg_hba.conf, используемые для загрузки начального состояния кластера, и на раннем этапе легко допустить ошибки.


И снова на помощь приходит patronictl:



patronictl -c /etc/patroni/18-demo.yml edit-config


Patroni загружает текущую конфигурацию DCS в текущий редактор по умолчанию, и в нашем случае она выглядит так:



check_timeline: true
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters: null
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 md5
- host all all ::1/128 md5
- host all all 192.168.6.10/16 md5
- local replication all peer
- host replication all 127.0.0.1/32 md5
- host replication all ::1/128 md5
- host replication all 192.168.6.10/16 md5
remove_data_directory_on_diverged_timelines: true
remove_data_directory_on_rewind_failure: true
use_pg_rewind: true
use_slots: true
retry_timeout: 10
ttl: 30


Используйте это как возможность исправить отсутствующие строки HBA или добавить любые параметры Postgres, которые должны применяться ко всем узлам. Например, добавьте wal_level в postgresql.parameters, чтобы включить логическую репликацию:



check_timeline: true
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters:
wal_level: logical
pg_hba:
- local all all peer
- host all all 127.0.0.1/32 md5
- host all all ::1/128 md5
- host all all 192.168.6.10/16 md5
- local replication all peer
- host replication all 127.0.0.1/32 md5
- host replication all ::1/128 md5
- host replication all 192.168.6.10/16 md5
remove_data_directory_on_diverged_timelines: true
remove_data_directory_on_rewind_failure: true
use_pg_rewind: true
use_slots: true
retry_timeout: 10
ttl: 30


Поскольку изменение параметра wal_level требует перезапуска Postgres, используйте patronictl для перезапуска узлов в кластере:



patronictl -c /etc/patroni/18-demo.yml restart 18-demo --force


Затем проверьте с помощью Postgres, что настройка изменилась, как ожидалось. Это вывод с узла 3, хотя я изменил DCS и перезапустил кластер с узла 1:



SHOW wal_level;

wal_level
-----------
logical


Завершение


Теперь вы знаете, почему эта серия была разбита на три части! Настройка Patroni сама по себе не слишком сложна, но правильная настройка конфигурации, знание того, как и почему работает каждый раздел, а также продолжение изменения кластера после развёртывания — это сложный процесс. Но если вы следовали инструкциям, у вас должен быть полностью работоспособный кластер Patroni прямо сейчас.


Технически вы можете остановиться здесь и пропустить третью и последнюю часть этой серии. Postgres поддерживает строки подключения с несколькими хостами, а указание read-write для target_session_attrs ограничивает подключения первичным узлом. Подключение с помощью psql может выглядеть так:



psql -d "user=postgres host=pg1,pg2,pg3 target_session_attrs=read-write"


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


Так что возвращайтесь на следующей неделе, чтобы узнать о HAProxy и о том, как он предоставляет этот критически важный последний компонент!



Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

No comments

The author does not allow comments to this entry

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.