Avanpost FAM/MFA+ : 4.1.3. Установка и настройка БД в отказоустойчивом (кластерном) исполнении

4.1.3. Установка и настройка БД в отказоустойчивом (кластерном) исполнении

Установка и настройка кластера PostgreSQL с репликацией автоматических переключений

Кластер PostgreSQL с репликацией автоматических переключений используется для обеспечения высокой доступности и отказоустойчивости базы данных PostgreSQL. Такое решение предназначено для минимизации простоев и обеспечения непрерывной работы системы даже при возникновении сбоев или отказов в оборудовании или программном обеспечении.

Описание

В данной инструкции описываются:

  • настройки кластера Postgres;
  • обработка событий падения нод с помощью службы repmgr;
  • настройка pbgouncer и автоматическая замена файла настроек;
  • смена IP-адреса при падении одного из балансировщика pgbouncer .

Рабочие директории:

ИмяДиректорияОписание
Postgresql 12/var/lib/pgsql/12/data/Рабочая директория Postgres
Replication settings/var/lib/pgsql/12/data/postgresql.replication.conf

Настройки репликации: в postgres.conf необходимо добавить 

include '/var/lib/pgsql/12/data/postgresql.replication.conf'

Repmgr settings/opt/repmgr/repmgr.confНастройки репликации, а также поведение при отключении нод


Настройка

Установка  и настройка repmgr и postgres

Для установки и настройки repmgr и postgres необходимо:

  1. Добавить репозиторий postgres на всех нодах: 

    sudo yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
  2. Установить дополнительные пакеты: 

    sudo yum -y install epel-release yum-utils
    sudo yum-config-manager --enable pgdg12
  3. На все ноды кластера установить следующие компоненты: 

    sudo yum install postgresql12 postgresql12-server repmgr_12
    sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
  4. Создать директорию и файл для логов утилиты repmgr и дать права пользователю postgres на всех нодах:

    mkdir /var/log/postgresql/
    
    nano /var/log/postgresql/repmgrd.log -> Сохраняем пустой файл.
    
    chown postgres:postgres -R /var/log/postgresql
  5. Отредактировать pg_hba.conf на обоих нодах по пути /var/lib/pgsql/12/data/pg_hba.conf:

    pg_hba.conf
    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    
    # "local" is for Unix domain socket connections only
    local   all             all                                     trust
    # IPv4 local connections:
    host    all             all             all            trust
    # IPv6 local connections:
    host    all             all             ::1/128                 trust
    # Allow replication connections from localhost, by a user with the
    # replication privilege.
    local   replication     all                                     peer
    host    replication     all             0.0.0.0/4            trust
    host    replication     all             c7node1                 trust
    host    replication     all             c7node2                 trust
    
    
  6. Отредактировать файл postgres.conf по пути /var/lib/pgsql/12/data/postgres.conf:

    postgresql.conf
    listen_addresses = '*'
    include 'postgresql.replication.conf'
  7. Создать файл /var/lib/pgsql/12/data/postgresql.replication.conf на node1:

    postgresql.replication.conf
    wal_level = replica
    max_wal_senders = 10
    max_replication_slots = 10
    hot_standby = on
    wal_log_hints = on
    archive_mode = on
    archive_command = '/bin/true'
  8. На одном из серверов создать базу данных:

    sudo -u postgres psql
    
    
    
    CREATE user repmgr password 'repmgr';
    CREATE DATABASE repmgr OWNER repmgr;
    ALTER USER repmgr WITH SUPERUSER;
    ALTER USER repmgr SET search_path TO repmgr, "$user", public;
    
    \q
  9. Создать файл repmgr.conf в директории /opt/repmgr/ на обоих серверах. Выдать права пользователю postgres на всю папку. В параметре node_name и в conninfo указать hostname каждого сервера. 

    mkdir /opt/repmgr
    nano /opt/repmgr/repmgr.conf

    Server1

    repmgr.conf
    node_id=1
    priority=100
    monitor_interval_secs = 2
    connection_check_type = 'ping'
    reconnect_attempts = 4
    reconnect_interval = 5
    node_name='c7node1'
    conninfo='host=c7node1 user=repmgr dbname=repmgr connect_timeout=2'
    data_directory='/var/lib/pgsql/12/data/'
    log_level='INFO'
    use_replication_slots=true
    monitoring_history=yes
    pg_bindir='/usr/pgsql-12/bin/'
    
    service_start_command   = 'sudo systemctl start postgresql-12'
    service_stop_command    = 'sudo systemctl stop postgresql-12'
    service_restart_command = 'sudo systemctl restart postgresql-12'
    service_reload_command  = 'sudo systemctl reload postgresql-12'
    #service_promote_command = 'pg_ctl  -w -D /var/lib/pgsql/12/data/  promote'
    promote_check_timeout = 15
    
    failover=automatic
    promote_command='/usr/pgsql-12/bin/repmgr standby promote -f /opt/repmgr/repmgr.conf --log-to-file'
    follow_command='/usr/pgsql-12/bin/repmgr standby follow -f /opt/repmgr/repmgr.conf --log-to-file --upstream-node-id=%n'
    repmgrd_service_start_command='sudo /bin/systemctl start repmgr-12'
    repmgrd_service_stop_command='sudo /bin/systemctl stop repmgr-12'
    
    
    log_file='/var/log/postgresql/repmgrd.log'

    Server2

    repmgr.conf
    node_id=2
    priority=80
    node_name='c7node2'
    monitor_interval_secs = 2
    connection_check_type = 'ping'
    reconnect_attempts = 4
    reconnect_interval = 5
    conninfo='host=c7node2 user=repmgr dbname=repmgr connect_timeout=2'
    data_directory='/var/lib/pgsql/12/data/'
    log_level='INFO'
    use_replication_slots=true
    monitoring_history=yes
    pg_bindir='/usr/pgsql-12/bin/'
    
    service_start_command   = 'sudo systemctl start postgresql-12'
    service_stop_command    = 'sudo systemctl stop postgresql-12'
    service_restart_command = 'sudo systemctl restart postgresql-12'
    service_reload_command  = 'sudo systemctl reload postgresql-12'
    #service_promote_command = 'sudo /usr/bin/pg_ctlcluster 10 main promote'
    #promote_check_timeout = 15
    
    failover=automatic
    promote_command='/usr/pgsql-12/bin/repmgr standby promote -f /opt/repmgr/repmgr.conf --log-to-file'
    follow_command='/usr/pgsql-12/bin/repmgr standby follow -f /opt/repmgr/repmgr.conf --log-to-file --upstream-node-id=%n'
    repmgrd_service_start_command='sudo /bin/systemctl start repmgr-12'
    repmgrd_service_stop_command='sudo /bin/systemctl stop repmgr-12'
    
    log_file='/var/log/postgresql/repmgrd.log'

    Выдача прав postgres на папку /opt/repmgr:

    chown postgres:postgres -R /opt/repmgr
    Далее действия выполняются под пользователем postgres.
  10. Выполнить регистрацию Server1 в качестве Master в репликационной системе с помощью repmgr:

    /usr/pgsql-12/bin/repmgr -f /opt/repmgr/repmgr.conf primary register
  11. Выполнить регистрацию Server2 в качестве Slave:

    Предварительно выключить службу postgresql-12, если она запущена.

    rm -Rf /var/lib/pgsql/12/data/
    
    /usr/pgsql-12/bin/repmgr -h c7node1 -U repmgr -d repmgr -f /opt/repmgr/repmgr.conf standby clone --dry-run
    
    /usr/pgsql-12/bin/repmgr -h c7node1 -U repmgr -d repmgr -f /opt/repmgr/repmgr.conf standby clone
    
    systemctl start postgresql-12
    
    /usr/pgsql-12/bin/repmgr -f /opt/repmgr/repmgr.conf standby register
  12. Проверить состояние кластера:

    /usr/pgsql-12/bin/repmgr -f /opt/repmgr/repmgr.conf cluster show
  13. Добавить пользователя postgres в sudoers:

    Defaults:postgres !requiretty
    %postgres ALL=(ALL)NOPASSWD:/bin/systemctl start postgresql-12,/bin/systemctl stop postgresql-12,/bin/systemctl restart postgresql-12,/bin/systemctl reload postgresql-12,/bin/systemctl start repmgr-12,/bin/systemctl stop repmgr-12
    
    
  14. Проверить работу переключения нод.
    Принудительно отключить службу postgres на Server1:

    sudo systemctl stop postgresql-12

     

  15. На node2 под пользователем postgres выполнить команду и проверить, переведена ли текущая реплика (node2) в режим Master (Primary):

    /usr/pgsql-12/bin/repmgr standby promote -f /opt/repmgr/repmgr.conf
  16. Перейти обратно на Server1.
    Под пользователем postgres произвести подключение ноды к кластеру, перевести текущую реплику в режим Slave ( StandBy):

    repmgr -f /opt/repmgr/repmgr.conf node rejoin --force-rewind -d 'host=c7node2 dbname=repmgr user=repmgr'
  17. Запустить службу postgres на Server1:

    sudo systemctl start postgresql-12

Настройка SSH между серверами

Действия выполняются под пользователем postgres.

Для настройки SSH между серверами необходимо:

  1. Сгенерировать ключ на обоих серверах:

    ssh-keygen -t rsa
  2. Вывести содержимое файла id_rsa.pub с серверов:

    cat /var/lib/pgsql/.ssh/id_rsa.pub
  3. На обоих серверах создать файл под пользователем postgres и дублировать содержимое из id_rsa.pub:

    nano /var/lib/pgsql/.ssh/authorized_keys

    Пример содержимого файла:

    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDeutr7h4ZfplM+mRjJY0iB6y1vwtpFgh6LoJSs50sDzzSbvIe61NOOb3dO+wQybBMNNnm8eGfTKOUniEn0PTGGbLt/s2mQous43zu0YiYaGlXk+IPJZzHU6lyWVp4/mcVKOEKKOjZnGeVP8tVMmWNMlZ26EEMPFOLt73ExyL585+NJzulFDCoZqWJETx9cQc4jRC7kzZpYe5N2Mvb3pWW7FBd5/0gZ2vUHlnvCka083IMwdKgvGXCBUNFqrxHR+5jljmBrg6t2lCP5bsrCl3Iya3mwi56zAusBdkUpxwuiehpn5eg0tY3olW+Qdtf7zygqFCwPFvaXDadldGNAyqw3 postgres@c7node1
    
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNSIuc3DaEfFb9w7hSI97ANqtYf2QncWPpVV9Ycsemgxz2SleqhFiiCAM+NLRhnl92uwRlgEDPvUrIz+EVtwOAabqr/Iy2BtQ1cjLQYUnRTXUezkaKelpY0lcB4HEXxiXzYnh+qsihFx14LCFjGkEnqfC5AmLlua4bQlskRgeEpJdnjDDndQqGu5O/cWIMKd9e/5m+qDEiAklnVFji5rSjgVz1MsK70oZQ4Y5YOaVetnkPpM6IraiMDVjIIcUtbwzfbZnPoGkx7qjphmXzrLc6/oKSeMHpQv3BF+8Ci8i910rFyy1AgZz/yBX+NmX3//ZSk0N2hPdZ1pPuTZz8DSI/ postgres@c7node2

Repmgr Service

Служба repmgr предназначена для автоматического переключения нод в кластере в режиме failover cluster. 

Для настройки службы repmgr необходимо:

  1. Под пользователем root добавить службу в автоматический запуск на обоих серверах:

    systemctl enable repmgr-12
  2. Поменять настройки службы в части подстановки конфигурационного файла repmgr.conf в настройке Environment=REPMGRDCONF или указав полный путь до файла в ExecStart:

    nano /usr/lib/systemd/system/repmgr-12.service
    # It's not recommended to modify this file in-place, because it will be
    # overwritten during package upgrades.  If you want to customize, the
    # best way is to create a file "/etc/systemd/system/repmgr.service",
    # containing
    #       .include /lib/systemd/system/repmgr.service
    #       ...make your changes here...
    # For more info about custom unit files, see
    # http://fedoraproject.org/wiki/Systemd#How_do_I_customize_a_unit_file.2F_add_a_custom_unit_file.3F
    
    [Unit]
    Description=A replication manager, and failover management tool for PostgreSQL
    After=syslog.target
    After=network.target
    After=postgresql-12.service
    
    [Service]
    Type=forking
    
    User=postgres
    Group=postgres
    
    # PID file
    PIDFile=/run/repmgr/repmgrd-12.pid
    
    # Location of repmgr conf file:
    Environment=REPMGRDCONF=/etc/repmgr/12/repmgr.conf
    Environment=PIDFILE=/run/repmgr/repmgrd-12.pid
    
    # Where to send early-startup messages from the server
    # This is normally controlled by the global default set by systemd
    # StandardOutput=syslog
    ExecStart=/usr/pgsql-12/bin/repmgrd -f /opt/repmgr/repmgr.conf -p ${PIDFILE} -d --verbose
    ExecStop=/usr/bin/kill -TERM $MAINPID
    ExecReload=/usr/bin/kill -HUP $MAINPID
    
    # Give a reasonable amount of time for the server to start up/shut down
    TimeoutSec=300
    
    [Install]
    WantedBy=multi-user.target
  3. Выполнить команду на обоих серверах

    systemctl daemon-reload
  4. Создать директорию, назначить владельца postgres:

    cd /run
    mkdir repmgr
    chown postgres:postgres repmgr
  5. Добавить в файл /var/lib/pgsql/12/data/postgresql.conf следующую строку и перезапустить службу postgres:
     

    shared_preload_libraries = 'repmgr'
    service postgresql-12 restart
  6. Под пользователем postgres проверить, все ли готово к запуску службы. Если уже существует запущенный процесс DETAIL: repmgrd PID is 23197удалить его, например, kill 23197

    /usr/pgsql-12/bin/repmgr -f /opt/repmgr/repmgr.conf daemon start --dry-run

Настройка балансировки запросов через pgbouncer 

Балансировка запросов через pgbouncer – процесс распределения запросов к базе данных PostgreSQL между несколькими экземплярами базы данных для улучшения производительности и повышения отказоустойчивости системы.

Описание

В данной инструкции описывается установка pgbouncer и схема развертывания в отказоустойчивом варианте. При выходе из строя одного из сервера с pgbouncer другой сервер будет принимать его IP-адрес и конфигурационный файл.

Настройка

Для настройки балансировки запросов через pgbouncer необходимо: 

  1. Установить pcs pacemaker corosync на всех серверах:

    yum install pcs pacemaker corosync
  2. Задать пароль для пользователя hacluster на обоих серверах:

     passwd hacluster
  3. Запустить и добавить в автозагрузку службу pcsd на обоих серверах:

    systemctl enable --now pcsd
  4. Проверить состояние серверов и произвести предварительную регистрацию на сервере №1:

    sudo pcs cluster auth c7node1 c7node2
  5. Создать кластер на сервере №1:

    sudo pcs cluster setup --name mycluster  c7node1 c7node2 --force
  6. Запустить кластер на сервере №1:

    sudo pcs cluster start
  7. Установить pgbouncer на обоих серверах:

    yum install pgbouncer
  8. Задать дополнительные параметры:

    sudo pcs property set stonith-enabled=false
    sudo pcs property set no-quorum-policy=ignore
  9. Сделать кластер доступным:

    sudo  pcs cluster enable --all
  10. Добавить службы в автозагрузку:

    sudo systemctl enable pcsd && sudo systemctl enable  corosync && sudo systemctl enable pacemaker
    sudo systemctl start pcsd && sudo systemctl start corosync && sudo systemctl start pacemaker
    
    
  11. Добавить\изменить настройку в файле /etc/pgbouncer/pgbouncer.ini на Node1 и Node2:

    listen_addr = *
    listen_port = 6432
    auth_type = trust
    auth_file = /etc/pgbouncer/userlist.txt
    #idp2 - пользователь для созданной вручную БД idp2 ( например для приложения FAM)
    admin_users = postgres, repmgr, idp
    stats_users = stats, postgres, repmgr, idp
    pool_mode = session
    max_client_conn = 5000
    %include /etc/pgbouncer/pgbouncer.database.ini
  12. Создать файл nano /etc/pgbouncer/pgbouncer.database.ini на Node1 и Node2:
    Node1

    [databases]
    #БД приложения, хост текущей мастер ноды
    idp2= host=c7node1
    • Node2

      [databases]
      #БД приложения, хост текущей мастер ноды
      idp2= host=c7node2




  13. Создать файл nano /etc/pgbouncer/userlist.txt , заполнить пользователями БД:

    "idp" "idp"
    "postgres" "postgres"
  14. Создать директорию scripts:

    mkdir /opt/scripts
  15. Создать скрипт для автоматической подстановки нового конфига с настройками подключения к БД и назначить пользователя "postgres" владельцем nano /opt/scripts/pgbouncer_promote.sh: 

    #!/usr/bin/env bash
    set -e
    set -u
    function try()
    {
        [[ $- = *e* ]]; SAVED_OPT_E=$?
        set +e
    }
    
    function throw()
    {
        exit $1
    }
    
    function catch()
    {
        export ex_code=$?
        (( $SAVED_OPT_E )) && set +e
        return $ex_code
    }
    
    function throwErrors()
    {
        set -e
    }
    
    function ignoreErrors()
    {
        set +e
    }
    ########################################
    
    PGBOUNCER_DATABASE_INI_NEW="/tmp/pgbouncer.database.ini"
    #ip-адрес или dns-имя серверов в кластере Postgres
    PGBOUNCER_HOSTS="10.10.180.56 10.10.180.59"
    #БД приложения
    DATABASES="idp"
    
    # Pause pgbouncer
    for h in ${PGBOUNCER_HOSTS}
    do
      for d in ${DATABASES}
      do
          try
    	  (psql -U postgres -h ${h} -p 6432 pgbouncer -tc "pause ${d}")
      done
    done
    
    # Promote server
    /usr/pgsql-12/bin/repmgr -f /opt/repmgr/repmgr.conf standby promote
    
    # Generate new config file for pgbouncer
    echo -e "[databases]\n" > ${PGBOUNCER_DATABASE_INI_NEW}
    for d in ${DATABASES}
    do
      echo -e "${d}= host=$(hostname -f)\n" >> ${PGBOUNCER_DATABASE_INI_NEW}
    done
    
    # Copy new config file, reload and resume pgbouncer
    for h in ${PGBOUNCER_HOSTS}
    do
      for d in ${DATABASES}
      do
          try
    	  (rsync -a ${PGBOUNCER_DATABASE_INI_NEW} ${h}:/etc/pgbouncer/pgbouncer.database.ini)
          try
    	  (psql -U postgres -h ${h} -p 6432 pgbouncer -tc "reload")
          try
    	  (psql -U postgres -h ${h} -p 6432 pgbouncer -tc "resume ${d}")
      done
    done
    
    rm ${PGBOUNCER_DATABASE_INI_NEW}
    
    
    sudo chown postgres:postgres -R /opt/scripts

Обсуждение