Patroni

Общее описание

Patroni — это Python-приложение для создания высокодоступных кластеров QHB на основе потоковой репликации. Оно используется такими компаниями как Red Hat, IBM Compose, Zalando и многими другими. С его помощью можно преобразовать систему из ведущего и ведомых узлов (primary — replica) в высокодоступный кластер с поддержкой автоматического контролируемого (switchover) и аварийного (failover) переключения. Patroni позволяет легко добавлять новые реплики в существующий кластер, поддерживает динамическое изменение конфигурации QHB одновременно на всех узлах кластера и множество других возможностей, таких как синхронная репликация, настраиваемые действия при переключении узлов, REST API, возможность запуска пользовательских команд для создания реплики.

Одна из возможных комбинаций стека технологий для организации высокодоступных кластеров:

  • QHB в качестве СУБД;
  • Patroni в качестве решения для кластеризации;
  • etcd или consul в качестве распределенного хранилища для Patroni.

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

etcd

Пример установки на CentOS 7: yum install etcd.

Также возможна установка через пакеты или исходный код по документации.

Рекомендуется устанавливать etcd на отдельных машинах, где не будет находится Patroni и QHB, так как для etcd очень важна нагрузка на диски. Для штатной работы кластера etcd минимальное количество нод - три. Для разработки и тестирования можно использовать одну ноду.

Consul

В связи с ограничениями Hashicorp на данный момент установка возможна только с использованием VPN.

Установка через пакеты с ресурса https://pkgs.org/download/consul, либо по документации.

Серверы Consul — это место, где хранятся и реплицируются данные Patroni. Поэтому рекомендованное минимальное количество нод - 3, для разработки и тестирования можно использовать 1 ноду. Для продуктивных высоконагруженных системы следует разворачивать сервисы Consul на отдельных от Patroni и QHB машинах.

Клиенты Consul также является членом системы и может подключаться к кластеру серверов Consul для получения информации об инфраструктуре. Клиента можно расположить на сервере с Patroni и QHB для подключения к кластеру серверов Consul через локального клиента Consul.

QHB

Установка через пакеты из репозитория QHB.

Не требуется создание и запуск сервиса QHB, а также инициализация кластера базы данных. Все управление кластером СУБД осуществляется через Patroni.

Patroni

Для работы Patroni требуется установить Python версии не ниже 3.6.

Для CentOS 8 установка Python происходит так:

dnf update -y
dnf install python3 -y
alternatives --set python /usr/bin/python3

Для работы Patroni требуется пакет psycopg2-binary:

python3.6 -m pip install -U pip
python3.6 -m pip install -U setuptools
pip3 install psycopg2-binary

Patroni требуется установить на тех же машинах, где и сервера QHB.

Установить Patroni можно через пакет из репозитория QHB:

  • dnf install patroni-qhb2.1.0-3.rhel7.x86_64 (для Centos 7);
  • dnf install patroni-qhb2.1.0-3.rhel8.x86_64 (для Centos 8).

Можно скачать rpm-пакет по следующим ссылкам и установить через утилиту rpm.

Для Centos 7:

https://repo.quantom.info/qhb/std-1/centos/7/x86_64/patroni-qhb2.1.0-3.rhel7.x86_64.rpm

rpm -i patroni-qhb2.1.0-3.rhel7.x86_64.rpm

Для Centos 8:

https://repo.quantom.info/qhb/std-1/centos/8/x86_64/patroni-qhb2.1.0-3.rhel8.x86_64.rpm
rpm -i patroni-qhb2.1.0-3.rhel8.x86_64.rpm

При необходимости, выполните установку недостающих необходимых пакетов, например для CentOS 7:

yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-PyYAML-3.13-1.el7.x86_64.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-psutil-5.6.7-1.el7.x86_64.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-click-6.7-8.el7.noarch.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-six-1.14.0-3.el7.noarch.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-dateutil-2.4.2-5.el7.noarch.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-prettytable-0.7.2-19.el7.noarch.rpm
yum install https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-7-x86_64/python3-cdiff-1.0-1.rhel7.noarch.rpm
yum install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python3-psycopg2-2.7.7-2.el7.x86_64.rpm
yum install https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-7-x86_64/python3-ydiff-1.2-10.rhel7.noarch.rpm

Для работы с базой etcd или consul, требуется установить зависимости для Patroni:

pip3 install patroni[etcd]

или

pip3 install patroni[consul]

Проверьте версию patroni:

patroni --version

Результат: patroni 2.1.0

Настройка

etcd

Выполняется независимо от Patroni и QHB, может быть выполнена предварительно (подробнее в официальной документации etcd). Для конфигурации каждого узла etcd, необходимо внести необходимые для запуска параметры в файл /etc/etcd/etcd.conf Также предварительно на каждом из узлов необходимо создать директорию под данные etcd, например /var/lib/etcd/default.etcd Ниже представлен пример минимальной конфигурации узлов на 3 машинах с адресами: X.X.X.101, X.X.X.102, X.X.X.103.

Для первого узла:

ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://X.X.X.101:2380"
ETCD_LISTEN_CLIENT_URLS="http://X.X.X.101:2379,http://127.0.0.1:2379"
ETCD_NAME="etcd0"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://X.X.X.101:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://X.X.X.101:2379"
ETCD_INITIAL_CLUSTER="etcd0=http://X.X.X.101:2380,etcd1=http://X.X.X.102:2380,etcd3=http://X.X.X.103:2380"
ETCD_INITIAL_CLUSTER_TOKEN="qhb_token"

Для второго узла:

ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://X.X.X.102:2380"
ETCD_LISTEN_CLIENT_URLS="http://X.X.X.102:2379,http://127.0.0.1:2379"
ETCD_NAME="etcd1"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://X.X.X.102:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://X.X.X..102:2379"
ETCD_INITIAL_CLUSTER="etcd0=http://X.X.X.101:2380,etcd1=http://X.X.X.102:2380,etcd3=http://X.X.X.103:2380"
ETCD_INITIAL_CLUSTER_TOKEN="qhb_token"

Для третьего узла:

ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://X.X.X.103:2380"
ETCD_LISTEN_CLIENT_URLS="http://X.X.X.103:2379,http://127.0.0.1:2379"
ETCD_NAME="etcd2"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://X.X.X.103:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://X.X.X.103:2379"
ETCD_INITIAL_CLUSTER="etcd0=http://X.X.X.101:2380,etcd1=http://X.X.X.102:2380,etcd3=http://X.X.X.103:2380"
ETCD_INITIAL_CLUSTER_TOKEN="qhb_token"

Базу данных etcd при пересоздании кластера нужно переинициализировать, удаляя данные в каталоге /var/lib/etcd/default.etcd.

Создайте сервис etcd на каждом из узлов для удобного управления кластером:

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
EnvironmentFile=-/etc/etcd/etcd.conf
User=etcd
# set GOMAXPROCS to number of processors
ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd --name=\"${ETCD_NAME}\" --data-dir=\"${ETCD_DATA_DIR}\" --listen-client-urls=\"${ETCD_LISTEN_CLIENT_URLS}\""
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Consul

Выполняется независимо от Patroni и QHB, может быть выполнена предварительно (подробнее в официальной документации consul). Для конфигурации каждого узла кластера серверов consul, необходимо внести необходимые для запуска параметры в файл /etc/consul.d/config.json.

Ниже представлен пример минимальной конфигурации узлов на 3 машинах. Адреса и доменные имена:

  • X.X.X.101, qhb-srv-01.quantom.local;
  • X.X.X.102, qhb-srv-02.quantom.local;
  • X.X.X.103, qhb-srv-03.quantom.local.

Для первого узла кластера серверов consul (для второго и третьего узла изменить bind_addr и client_addr):

{
     "bind_addr": "X.X.X.101",
     "bootstrap_expect": 3,
     "client_addr": "X.X.X.101",
     "datacenter": "dc1",
     "data_dir": "/opt/consul",
     "domain": "consul",
     "enable_script_checks": true,
     "dns_config": {
         "enable_truncate": true,
         "only_passing": true
     },
     "enable_syslog": true,
     "encrypt": "v6+HtK6JQ6kX2XgYkSFQM9KFXF1YeGyFHcRo6hWZbjI=",
     "leave_on_terminate": true,
     "log_level": "INFO",
     "rejoin_after_leave": true,
     "retry_join": [
         "qhb-srv-01.quantom.local",
         "qhb-srv-02.quantom.local",
         "qhb-srv-03.quantom.local"
     ],
     "server": true,
     "start_join": [
         "qhb-srv-01.quantom.local",
         "qhb-srv-02.quantom.local",
         "qhb-srv-03.quantom.local"
     ],
    "ui_config": { "enabled": true }
}

Для подключения к кластеру серверов consul можно создать клиента consul (например, разместить на серверах с Patroni). При такой конфигурации Patroni подключается к локальному клиенту consul, который обращается ко всему кластеру серверов consul.

Для конфигурации клиента consul, необходимо внести необходимые для запуска параметры в файл /etc/consul.d/config.json.

Пример минимальной конфигурации клиента:

{
     "bind_addr": "X.X.X.104",
     "client_addr": "X.X.X.104",
     "datacenter": "dc1",
     "node_name": "client01",
     "data_dir": "/opt/consul",
     "domain": "consul",
     "enable_script_checks": true,
     "dns_config": {
         "enable_truncate": true,
         "only_passing": true
     },
     "enable_syslog": true,
     "encrypt": "v6+HtK6JQ6kX2XgYkSFQM9KFXF1YeGyFHcRo6hWZbjI=",
     "leave_on_terminate": true,
     "log_level": "INFO",
     "rejoin_after_leave": true,
     "retry_join": [
         "qhb-srv-01.quantom.local",
         "qhb-srv-02.quantom.local",
         "qhb-srv-03.quantom.local"
     ],
     "server": false,
     "start_join": [
         "qhb-srv-01.quantom.local",
         "qhb-srv-02.quantom.local",
         "qhb-srv-03.quantom.local"
     ],
    "ui_config": { "enabled": true }
}

Каждую конфигурацию необходимо проверить на валидность:

consul validate /etc/consul.d/config.json

Создайте сервис consul на каждом из узлов для удобного управления кластером:

[Unit]
Description=Consul Service Discovery Agent
Documentation=https://www.consul.io/
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=consul
Group=consul
ExecStart=/usr/bin/consul agent \
    -node=qhb-srv-01.quantom.local \
    -config-dir=/etc/consul.d
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
TimeoutStopSec=5
Restart=on-failure
SyslogIdentifier=consul

[Install]
WantedBy=multi-user.target

Patroni

На каждом хосте с Patroni необходимо создать директорию под кластер баз данных QHB и раздать необходимые права пользователю qhb, например /mnt/patroni:

mkdir -p /mnt/patroni
chown qhb:qhb /mnt/patroni
chmod 700 /mnt/patroni

Создайте конфигурационный файл с расширением .yml на каждом хосте с Patroni. Подробнее, о параметрах конфигурации, в документации.

Кроме основных параметров конфигурации, указанных в документации Patroni, в релизе patroni-qhb2.1.0-3 добавлены дополнительные параметры для управления QHB:

#QHB parameters
  hba_file: qhb_hba.conf
  ident_file: qhb_ident.conf
  database: qhb
  config_base_name: qhb

Ниже представлен пример минимальной конфигурации кластера Patroni на 2 хостах с адресами: X.X.X.104, X.X.X.105.

В примере указаны параметры подключения к etcd, для работы с consul - раскомментируйте и добавьте необходимые строки

qhb0.yml для первого узла кластера Patroni:

scope: cluster
#namespace: /service/
name: qhb0

restapi:
  listen: 127.0.0.1:8008
  connect_address: 127.0.0.1:8008

etcd:
#Use "hosts" to provide multiple endpoints
  hosts:
  - X.X.X.101:2379
  - X.X.X.102:2379
  - X.X.X.103:2379

#consul:
  #host: X.X.X.104:8500

bootstrap:
  # this section will be written into etcd/Consul:/<namespace>/<scope>/config after initializing new cluster
  # and all other cluster members will use it as a `global configuration`
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
  # some desired options for 'initdb'
  initdb:  # Note: It needs to be a list (some options need values, others are switches)
  - encoding: UTF8
  - data-checksums

  pg_hba:  # Add following lines to qhb_hba.conf after running 'initdb'
  - host replication replicator 127.0.0.1/32 md5
  - host replication replicator X.X.X.0/24 md5
  - host all all 0.0.0.0/0 md5

  # Some additional users users which needs to be created after initializing new cluster
  users:
    admin:
      password: admin
      options:
        - createrole
        - createdb
postgresql:
  listen: 127.0.0.1,X.X.X.104,::1:5432
  connect_address: X.X.X.104:5432
  data_dir: /mnt/patroni
  bin_dir: /usr/local/qhb/bin
  pgpass: /tmp/pgpass0
  authentication:
    replication:
      username: replicator
      password: rep-pass
    superuser:
      username: qhb
      password: qhb
    rewind:  
      username: rewind_user
      password: rewind_password
  parameters:
    unix_socket_directories: '.'
  # QHB parameters
  hba_file: qhb_hba.conf
  ident_file: qhb_ident.conf
  database: qhb
  config_base_name: qhb

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false

qhb1.yml для второго узла кластера Patroni:

scope: cluster
#namespace: /service/
name: qhb1

restapi:
  listen: 127.0.0.1:8008
  connect_address: 127.0.0.1:8008

etcd:
#Use "hosts" to provide multiple endpoints
  hosts:
  - X.X.X.101:2379
  - X.X.X.102:2379
  - X.X.X.103:2379

#consul:
  #host: X.X.X.105:8500

bootstrap:
  # this section will be written into etcd/Consul:/<namespace>/<scope>/config after initializing new cluster
  # and all other cluster members will use it as a `global configuration`
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
  # some desired options for 'initdb'
  initdb:  # Note: It needs to be a list (some options need values, others are switches)
  - encoding: UTF8
  - data-checksums

  pg_hba:  # Add following lines to qhb_hba.conf after running 'initdb'
  - host replication replicator 127.0.0.1/32 md5
  - host replication replicator X.X.X.0/24 md5
  - host all all 0.0.0.0/0 md5

  # Some additional users users which needs to be created after initializing new cluster
  users:
    admin:
      password: admin
      options:
        - createrole
        - createdb
postgresql:
  listen: 127.0.0.1,X.X.X.105,::1:5432
  connect_address: X.X.X.105:5432
  data_dir: /mnt/patroni
  bin_dir: /usr/local/qhb/bin
  pgpass: /tmp/pgpass0
  authentication:
    replication:
      username: replicator
      password: rep-pass
    superuser:
      username: qhb
      password: qhb
    rewind:  
      username: rewind_user
      password: rewind_password
  parameters:
    unix_socket_directories: '.'
  # QHB parameters
  hba_file: qhb_hba.conf
  ident_file: qhb_ident.conf
  database: qhb
  config_base_name: qhb

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false

Создайте сервис patroni на каждом из узлов для удобного управления кластером Patroni:

# This is an example systemd config file for Patroni
# You can copy it to "/etc/systemd/system/patroni.service",
[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target
[Service]
Type=simple
User=qhb
Group=qhb
# Read in configuration file if it exists, otherwise proceed
EnvironmentFile=-/etc/patroni_env.conf
WorkingDirectory=~
# Where to send early-startup messages from the server
# This is normally controlled by the global default set by systemd
#StandardOutput=syslog
# Pre-commands to start watchdog device
# Uncomment if watchdog is part of your patroni setup
#ExecStartPre=-/usr/bin/sudo /sbin/modprobe softdog
#ExecStartPre=-/usr/bin/sudo /bin/chown postgres /dev/watchdog
# Start the patroni process
ExecStart=/usr/bin/patroni /opt/qhb0.yml
# Send HUP to reload from patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID
# only kill the patroni process, not it's children, so it will gracefully stop postgres
KillMode=process
# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec=30
# Do not restart the service if it crashes, we want to manually inspect database on failure
Restart=no
[Install]
WantedBy=multi-user.target

Запуск компонентов

etcd

Предварительно убедитесь, что у вас добавлены необходимые правила в firewall. Для запуска etcd через сервис, на всех узлах необходимо выполнить systemctl start etcd команда на всех узлах завершится, когда узлы найдут друг друга, т.е. когда команда будет выполнена на втором и третьем хосте. При пересоздании кластера нужно предварительно очистить базы etcd.

Состав кластера etcd можно посмотреть командой etcdctl member list.

Consul

Предварительно убедитесь, что у вас добавлены необходимые правила в firewall.

Для запуска etcd через сервис, на всех узлах серверов и клиентах необходимо выполнить systemctl start consul.

По адресу http(s) любого участника кластера, например: http://X.X.X.101:8500 , можно посмотреть состав кластера (сервера и клиенты) и текущего лидера. Подробнее в официальной документации Consul.

Patroni

Предварительно убедитесь, что у вас добавлены необходимые правила в firewall.

Запуск необходимо производить только после запуска распределенного хранилища - etcd/consul.

Для запуска etcd через сервис, на всех узлах необходимо выполнить systemctl start patroni.

Состояние и состав кластера Patroni можно посмотреть на любом узле, например patronictl -c /opt/qhb0.yml list.

При штатной работе вы увидите State - running у всех участников кластера.

Работа, переключение

При остановке работы СУБД на хосте 104, СУБД на хосте 105 становится лидером.

При включении в работу СУБД на хосте 104, она становится репликой.

Если останавливается работа мастера на хосте 105, мастером становится хост 104.

См. также