PostgreSQL 10 — Потоковая репликация с отработкой фейловера

20220414-090846postgresql

PostgreSQL 10 — Потоковая репликация с отработкой фейловера. Данная запись посвящается исключительно «Потоковой репликации», не архивированию, не логической репликации, не восстановлению из бэкапа. Тут описывается потоковая репликация, настройка одного мастера, одного слейва и переключение между ними. Репликация — не бэкап.

  • В случае если вы на мастере убили базу, это изменение переедет в реплику.
  • Так же если у вас нету бэкапа убитой базы — вероятно вас повесят.
  • Если у вас в процессе работы упал мастер, например сдох диск, сгорел сервер, на часть здания в которой располагался мастер — упал метеорит. Вас спасет репликация.

Репликация PostgreSQL 10 — это когда вы превращаете слейв в текущий мастер и продолжаете радаснаработать с минимально возможным оставанием текущего мастера от старого мастера на момент выхода из строя и минимальным временем простоя.

Даже если вы просто не знаете что произошло с мастером но уверены что в ближайшие секунды он не заработает — вы можете превратить слейв в мастер для восстановления работы. А уже потом вы будете разбираться с тем что случилось с прошлым мастером. Главное не допустить существования в вашей сети двух рассинхронизированных мастеров. Тогда вас тоже повесят 🙂

Не смотрите на то что запись получилось достаточно объемной. Она приняла такие масштабы исключительно по причине желания сделать её более понятной и рассмотреть все ситуации работы данной схемы. Сам процесс — это пара десятков команд на обоих серверах и пара минут времени.

Исходные данные:

  • Два хоста настроенные по этой инструкции: Ubuntu 18.04 — Установка PostgreSQL 10 для 1С
  • 2 Ядра + 16GB Ram + 32GB SSD у каждого (Не потому что так надо, а потому что это стенд, параметры продакшена надо смотреть по фактической нагрузке)
  • Имя мастера: ag-psql10-s1 / IP 192.168.1.231
  • Имя слейва: ag-psql10-s2 / IP 192.168.1.232
  • Пароль пользователя postgres h4GiQn
  • Пароль пользователя replica 4UtKbw
  • Все данные которые есть на слейве — будут удалены и заменены данными мастера. Включая и пользователей. Это важно! Не убейте свои ценные данные.
  • Данные pg_hba.conf и postgresql.conf не реплицируются, их придется настраивать ручками

PostgreSQL 10 — Потоковая репликация — Настраиваем мастер

  1. Создаем пользователя репликации

     
     
     
     
    sudo su postgres #В этот момент мы авторизовываемся под пользователем postgres
    psql
    postgres=# CREATE USER replica REPLICATION LOGIN CONNECTION LIMIT 2 ENCRYPTED PASSWORD '4UtKbw';
    \q
     

    У данного пользователя в postgresql будет пароль 4UtKbw и лимит в 2 одновременных подключения. Помним что если в pg_hba.conf у нас настроено следующим образом:

     
     
     
     
    # Database administrative login by Unix domain socket
    local all postgres md5
     

    То при вводе команды

    psql
    система попросит вас ввести пароль вашего пользователя postgres в postgresql. У меня он h4GiQn. Если у вас просит пароль, но вы не помните его, надо изменить md5 на trust, перезапустить постгрес и вас пустит без пароля.

     

     

  2. Бэкапим pg_hba.conf

     
     
     
     
    #будучи всё еще авторизованными под пользователем postgres
    cp /etc/postgresql/10/main/pg_hba.conf /etc/postgresql/10/main/pg_hba.bkp
     
  3. Редактируем pg_hba.conf

     
     
     
     
    #будучи всё еще авторизованными под пользователем postgres
    nano /etc/postgresql/10/main/pg_hba.conf
     

    Приводим раздел репликации к такому виду:

     
     
     
     
    #Настройки pg_hba.conf для ag-psql10-s1
    # Allow replication connections from localhost, by a user with the
    # replication privilege.
    #local replication all peer
    #host replication all 127.0.0.1/32 md5
    #host replication all ::1/128 md5
    host replication replica 192.168.1.232/32 md5
     

    Мы указываем что репликация разрешена пользователю с именем replica, подключающемуся с адреса 192.168.1.232 с авторизацией по паролю
    Сохраняем внесенные изменения командой Ctrl+O, закрываем nano командой Ctrl+X

  4. Бэкапим postgresql.conf

     
     
     
     
    #будучи всё еще авторизованными под пользователем postgres
    cp /etc/postgresql/10/main/postgresql.conf /etc/postgresql/10/main/postgresql.bkp
     
  5. Редактируем postgresql.conf

     
     
     
     
    #будучи всё еще авторизованными под пользователем postgres
    nano /etc/postgresql/10/main/postgresql.conf
     

    Для того чтобы быстро находить нужные нам параметры, можно использовать поиск, активируемый комбинацией Ctrl+W

     
     
     
     
    listen_addresses = '*'
    hot_standby = on
    wal_level = replica
    max_wal_senders = 10
    wal_keep_segments = 32
     

    Приводим параметры к указанному выше виду.
    Немного комментариев:

    • listen_addresses
      Этот параметр отвечает за то на каких интерфейсах PostgresSQL будет принимать клиентские подключения. Я оставлю ‘*’, что значит ВСЕ
    • hot_standby
      Если очень поверхностно — этот параметр отвечает за то, можно ли читать данные слейва. Например для какой-нибудь умной аналитической нагрузки которой не надо записывать данные в базу. В случае с 1Ской можно сделать off. В случае каскадной репликации придется оставить on. Я оставлю on.
    • wal_level
      Отвечает за количество информации записываемой в WAL. Для репликации необходимо значение replica. Возможны значения minimal и для логической репликации logical. По объему данных оно выглядит как: minimal < replica < logical. Нам надо replica
    • max_wal_senders
      Отвечает за количество одновременно подключенных слейвов у мастера. По умолчанию 10, если 0 — репликация отключается. У нас будет один слейв. Можно либо оставить 10, либо указать 1. Я оставлю 10
    • wal_keep_segments
      1 сегмент = 16 метров. Сколько сегментов будет указано хранить здесь, столько postgres сохранит прежде чем при добавлении следующего удалить самый старый сегмент. Если к моменту удаления слейв не успеет всосать всё еще нужный ему WAL — реплика будет остановлена и по сути её нужно будет настраивать заново закачивая данные через pg_backup. Сколько ставить зависит от того сколько у вас свободного места, но ставить больше 64 я бы не рекомендовал (это 1 гиг). Я поставлю 32. Стандартное значение = 0.
  6. Перезапускаем postgres

     
     
     
     
    #будучи всё еще авторизованными под пользователем postgres
    service postgresql restart #система попросит ввести пароль вашей админской учетки
    exit
     
    • PostgreSQL 10 — Потоковая репликация — Настраиваем слейв

      1. Останавливаем postgresql

         
         
         
         
        sudo su postgres
        service postgresql stop #система попросит ввести пароль вашей админской учетки
         
      2. Удаляем текущие данные

         
         
         
         
        #будучи всё еще авторизованными под пользователем postgres
        rm -R /var/lib/postgresql/10/main/
         

        Для того чтобы инициализировать репликацию, необходимо скачать с сервера свежую копию данных. Иначе если разрыв данных будет слишком велик (больше чем доступно данных согласно wal_keep_segments), репликация попросту не запустится.

      3. Закачиваем данные с мастера

         
         
         
         
        #будучи всё еще авторизованными под пользователем postgres
        pg_basebackup -P -R -X stream -c fast -h 192.168.1.231 -U replica -D /var/lib/postgresql/10/main/
        service postgresql start #система попросит ввести пароль вашей админской учетки
         

        Система запросит пароль от пользователя replica. Когда мы изначально создавали этого пользователя на мастере, мы назначили ему пароль 4UtKbw.
        Дожидаемся окончания загрузки.

      4. Настраиваем revocery.conf

        После использования команды pg_basebackup на слейве автоматом был создан файл /var/lib/postgresql/10/main/recovery.conf с настройками репликации

         
         
         
         
        nano /var/lib/postgresql/10/main/recovery.conf
        #В файле мы увидим две строки:
        standby_mode = 'on'
        primary_conninfo = 'user=replica password=4UtKbw host=192.168.1.231 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres target_session_attrs=any'
        #Добавляем триггер файл
        trigger_file = '/tmp/to_master'
         
        • standby_mode = ‘on’ — значит что сервер является резервным и после скачивания последнего WAL файла продолжит пытаться скачивать их используя данные из primary_conninfo
        • primary_conninfo — строка подключения слейва к мастеру
        • trigger_file — путь к файлу, наличие которого, в случае работы сервера в режиме репликации тут же заставит его превратиться в мастер и выйти из режима READONLY.
      5. Приводим раздел репликации СЛЕЙВА к такому виду:

         
         
         
         
        #будучи всё еще авторизованными под пользователем postgres
        nano /etc/postgresql/10/main/pg_hba.conf
        #Настройки pg_hba.conf для ag-psql10-s2
        # Allow replication connections from localhost, by a user with the
        # replication privilege.
        #local replication all peer
        #host replication all 127.0.0.1/32 md5
        #host replication all ::1/128 md5
        host replication replica 192.168.1.231/32 md5
         

        На слейве в pg_hba.conf мы указываем IP адрес ag-psql10-s1, чтобы когда он станет слейвом он смог инициализировать подключение пользователя replica

      6. Запускаем слейв

         
         
         
         
        #будучи всё еще авторизованными под пользователем postgres
        service postgresql start
         

         

    • PostgreSQL 10 — Потоковая репликация — Проверяем репликацию

      1. Создаем на мастере тестовую базу данных

         
         
         
         
        sudo su postgres #Если вдруг мы авторизованы под другим пользователем
        psql #Запускаем psql, вводим пароль если авторизация стоит md5
        CREATE DATABASE replica_test_ok;
         

         

      2. Смотрим результат на слейве

         
         
         
         
        sudo su postgres #Если вдруг мы авторизованы под другим пользователем
        psql #Запускаем psql, вводим пароль если авторизация стоит md5
        postgres=# \l
        Список баз данных
        Имя | Владелец | Кодировка | LC_COLLATE | LC_CTYPE | Права доступа
        -----------------+----------+-----------+-------------+-------------+-----------------------
        postgres | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        replica_test_ok | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        template0 | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 | =c/postgres +
        | | | | | postgres=CTc/postgres
        template1 | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 | =c/postgres +
        | | | | | postgres=CTc/postgres
        (4 строки)
         

        Всё ок, можно создать или удалить еще какую-нибудь базу или таблицу на мастере и данные тут же приедут на реплику (к слову о том что будет если вы убьете в продакшене базу на мастере не имея её бекапа)

    • PostgreSQL 10 — Потоковая репликация — Отрабатываем фейловер ag-psql10-s1 => ag-psql10-s2

      Итак, мы настроили репликацию. Наш мастер: ag-psql10-s1, наш слейв: ag-psql10-s2. Теперь мы отработаем фейловер в процессе которого ag-psql10-s1 умрёт и роль мастера уедет на ag-psql10-s2.

      1. Для наглядности создадим на мастере новую базу

         
         
         
         
        sudo su postgres
        psql
        CREATE DATABASE failover_s1_to_s2_test_ok;
        \q
        exit
         
      2. Выключаем мастер

         
         
         
         
        sudo service postgresql stop
        #или если хочется прям ваще по жести то вместо остановки постгреса убьем весь сервер
        sudo shutdown -h now
         
      3. Проверяем слейв ag-psql10-s2

         
         
         
         
        sudo su postgres
        psql
        postgres=# \l
        Список баз данных
        Имя | Владелец | Кодировка | LC_COLLATE | LC_CTYPE | Права доступа
        ---------------------------+----------+-----------+-------------+-------------+-----------------------
        failover_s1_to_s2_test_ok | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        postgres | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        replica_test_ok | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        template0 | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 | =c/postgres +
        | | | | | postgres=CTc/postgres
        template1 | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 | =c/postgres +
        | | | | | postgres=CTc/postgres
         

        На нем должна быть созданная нами на мастере база failover_s1_to_s2_test_ok
        Пытаемся создать в нем базу данных

         
         
         
         
        postgres=# CREATE DATABASE test;
        ОШИБКА: в транзакции в режиме "только чтение" нельзя выполнить CREATE DATABASE
        \q #выходим из psql
         

        Видим отказ, т.к. слейв еще не знает что мастер умер

      4. Создаем триггер файл и превращаем ag-psql10-s2 в новый мастер

        Помним что в recovery.conf триггер файлом мы указали файл «/tmp/to_master»
        Создаем этот файл

         
         
         
         
        # Не имеет значения авторизованы вы под postgres или под какой либо другой учеткой.
        # В данном случае я выполняю команду из под postgres
        touch /tmp/to_master
         

        Пытаемся снова создать базу

         
         
         
         
        postgres=# CREATE DATABASE failover_s1_to_s2_complete;
        CREATE DATABASE
         

        Видим что база успешно создана. Мастер умер! Даздравствует новый Мастер! В этот момент клиенты уже могут набигать на новый мастер

      5. Переключаем клиентские приложения на новый мастер

        1. Я предпочитаю менять DNS запись. У меня есть отдельное имя psql_master где прописан айпишник текущего мастера
        2. Можно поменять айпиадрес мастера
        3. Или поменять в приложениях настройки подключений со старого мастера на новый
        4. А лучше поднять специальный балансировщик и настраивать все подключения на него, а он уже автоматом будет перенаправлять запросы на действующего мастера
          на вкус и цвет, я ленивый пользуюсь первым способом но ищу в себе силы поднять 4й способ. Способы 2 и 3 для тех кто любит знатно подрочить.
    • PostgreSQL 10 — Потоковая репликация — Превращаем старый мастер ag-psql10-s1 в слейв

      После того как мы перенесли роль мастера на ag-psql10-s2, наш почивший мастер ag-psql10-s1 не в курсе последних событий, и как только он стартанет — он начнет активно принимать подключения и писать в себя данные. Ну а клиентам плевать куда писать, им куда дадут они туда и пишут. Поэтому если часть клиентов уже пишет на s2, а часть например еще не в курсе что в сети новый хозяин, в случае пробуждения пребывающего в таком же неведнии s1, мы рискуем получить в сети 2 мастера. Этим и хорош способ со сменой адреса DNS имени, что клиент сам не подозревая переключится на новый мастер. В любом случае сразу же после включения нам надо вырубить постгрес на старом мастере

      sudo service postgresql stop
      , а дальше тихо мирно продолжать конфигурировать его в новый слейв.

       

      1. Стераем директорию main и закачиваем с нового мастера.

        Это та же команда что и ранее только IP изменен на новый. На ag-psql10-s2 сейчас полная копия данных с ag-psql10-s1 до его выхода из строя. Включая пользователей и пароли.

         
         
         
         
        sudo su postgres
        rm -R /var/lib/postgresql/10/main/
        pg_basebackup -P -R -X stream -c fast -h 192.168.1.232 -U replica -D /var/lib/postgresql/10/main/
         

        На новом мастере при отработке фейловера файл recovery.conf переименовался в recovery.done, он так же будет закачан, его нужно удалить

         
         
         
         
        rm /var/lib/postgresql/10/main/recovery.done
         

        При синхронизации pg_basebackup снова создала нам recovery.conf с актуальными параметрами подключения. Прописываем туда trigger_file

         
         
         
         
        nano /var/lib/postgresql/10/main/recovery.conf
        standby_mode = 'on'
        primary_conninfo = 'user=replica password=4UtKbw host=192.168.1.231 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres target_session_attrs=any'
        #Добавляем триггер файл
        trigger_file = '/tmp/to_master'
         
      2. Запускаем новый слейв ag-psql10-s1

         
         
         
         
        service postgresql start
         

         

      3. Проверяем что он в режиме READONLY

         
         
         
         
        psql
        postgres=# create database qwe;
        ОШИБКА: в транзакции в режиме "только чтение" нельзя выполнить CREATE DATABASE
         
      4. На текущем мастере ag-psql10-s2 создаем тестовую БД

         
         
         
         
        postgres=# CREATE DATABASE master_to_slave_config_ok;
        CREATE DATABASE
         
      5. Смотрим результат на слейве

         
         
         
         
        postgres-# \l
        Список баз данных
        Имя | Владелец | Кодировка | LC_COLLATE | LC_CTYPE | Права доступа
        ----------------------------+----------+-----------+-------------+-------------+-----------------------
        failover_s1_to_s2_complete | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        failover_s1_to_s2_test_ok | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        master_to_slave_config_ok | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        postgres | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        replica_test_ok | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 |
        template0 | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 | =c/postgres +
        | | | | | postgres=CTc/postgres
        template1 | postgres | UTF8 | ru_RU.UTF-8 | ru_RU.UTF-8 | =c/postgres +
        | | | | | postgres=CTc/postgres
        (7 строк)
         

        База приехала! Yaaaay!

    • PostgreSQL 10 — Потоковая репликация — Отрабатываем фейловер ag-psql10-s2 => ag-psql10-s1

      Собсно действия абсолютно такие же как в случае ag-psql10-s1 => ag-psql10-s2.

      1. Убиваем мастер s2 в случае если он сам не умер
      2. Создаём на слейве s1 триггер файл:
        touch /tmp/to_master
        . Слейв становится мастером. Можно проверить что он начал принимать команды записи.
      3. Переподключаем клиенты на новый мастер s1
      4. Запускаем старый мастер s2 и выключаем на нем postgresql если запущена
        sudo service postgresql stop
      5. Удаляем старую базу
         
         
         
         
        sudo su postgres
        rm -R /var/lib/postgresql/10/main/
         
      6. Закачиваем новую базу
         
         
         
         
        pg_basebackup -P -R -X stream -c fast -h 192.168.1.231 -U replica -D /var/lib/postgresql/10/main/
         

        Внимательно проверяем что указан IP адрес текущего мастера, теперь это 192.168.1.231 (ag-psql10-s1)

      7. Удаляем recovery.done
         
         
         
         
        rm /var/lib/postgresql/10/main/recovery.done
         
      8. Добавляем в recovery.conf триггер
         
         
         
         
        nano /var/lib/postgresql/10/main/recovery.conf
        standby_mode = 'on'
        primary_conninfo = 'user=replica password=4UtKbw host=192.168.1.231 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres target_session_attrs=any'
        #Добавляем триггер файл
        trigger_file = '/tmp/to_master'
         
      9. Запускаем текущий слев
         
         
         
         
        service postgresql start
         
      10. По окончании имеем исходный вариант работы.

     

    Собственно вот и все дела. Если есть какие-то вопросы — не стесняйтесь задавать их в комментариях.

    P.S. Лучше обкатать 2 фейловера, с мастера на слейв с полной передачей ролей и обратно. Делается это за тем, чтобы проверить все конфиги в контролируемой среде. До того, как что-то реально сломается.

 

×
Stay Informed

When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.

Как расширить корневую файловую систему с помощью ...
Автозагрузка Openvpn systemd linux