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

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 - Перезапускаем мастер после настройки

      Перезапускаем мастер после настройки

  • 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 фейловера, с мастера на слейв с полной передачей ролей и обратно. Делается это за тем, чтобы проверить все конфиги в контролируемой среде. До того, как что-то реально сломается.

Text.ru - 100.00%

JOIN THE DISCUSSION