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 — Потоковая репликация — Настраиваем мастер
-
Создаем пользователя репликации
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
То при вводе команды
система попросит вас ввести пароль вашего пользователя postgres в postgresql. У меня он h4GiQn. Если у вас просит пароль, но вы не помните его, надо изменить md5 на trust, перезапустить постгрес и вас пустит без пароля.psql
-
Бэкапим pg_hba.conf
#будучи всё еще авторизованными под пользователем postgrescp /etc/postgresql/10/main/pg_hba.conf /etc/postgresql/10/main/pg_hba.bkp
-
Редактируем pg_hba.conf
#будучи всё еще авторизованными под пользователем postgresnano /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 -
Бэкапим postgresql.conf
#будучи всё еще авторизованными под пользователем postgrescp /etc/postgresql/10/main/postgresql.conf /etc/postgresql/10/main/postgresql.bkp
-
Редактируем postgresql.conf
#будучи всё еще авторизованными под пользователем postgresnano /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. Нам надо replicamax_wal_senders
Отвечает за количество одновременно подключенных слейвов у мастера. По умолчанию 10, если 0 — репликация отключается. У нас будет один слейв. Можно либо оставить 10, либо указать 1. Я оставлю 10wal_keep_segments
1 сегмент = 16 метров. Сколько сегментов будет указано хранить здесь, столько postgres сохранит прежде чем при добавлении следующего удалить самый старый сегмент. Если к моменту удаления слейв не успеет всосать всё еще нужный ему WAL — реплика будет остановлена и по сути её нужно будет настраивать заново закачивая данные через pg_backup. Сколько ставить зависит от того сколько у вас свободного места, но ставить больше 64 я бы не рекомендовал (это 1 гиг). Я поставлю 32. Стандартное значение = 0.
-
Перезапускаем postgres
#будучи всё еще авторизованными под пользователем postgresservice postgresql restart
#система попросит ввести пароль вашей админской учеткиexit
-
PostgreSQL 10 — Потоковая репликация — Настраиваем слейв
-
Останавливаем postgresql
sudo su postgres
service postgresql stop #система попросит ввести пароль вашей админской учетки
-
Удаляем текущие данные
#будучи всё еще авторизованными под пользователем postgresrm -R /var/lib/postgresql/10/main/
Для того чтобы инициализировать репликацию, необходимо скачать с сервера свежую копию данных. Иначе если разрыв данных будет слишком велик (больше чем доступно данных согласно wal_keep_segments), репликация попросту не запустится.
-
Закачиваем данные с мастера
#будучи всё еще авторизованными под пользователем postgrespg_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.
Дожидаемся окончания загрузки. -
Настраиваем 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_conninfoprimary_conninfo
— строка подключения слейва к мастеруtrigger_file
— путь к файлу, наличие которого, в случае работы сервера в режиме репликации тут же заставит его превратиться в мастер и выйти из режима READONLY.
-
Приводим раздел репликации СЛЕЙВА к такому виду:
#будучи всё еще авторизованными под пользователем postgresnano /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 md5host replication replica 192.168.1.231/32 md5
На слейве в pg_hba.conf мы указываем IP адрес ag-psql10-s1, чтобы когда он станет слейвом он смог инициализировать подключение пользователя replica
-
Запускаем слейв
#будучи всё еще авторизованными под пользователем postgresservice postgresql start
-
-
PostgreSQL 10 — Потоковая репликация — Проверяем репликацию
-
Создаем на мастере тестовую базу данных
sudo su postgres
#Если вдруг мы авторизованы под другим пользователемpsql
#Запускаем psql, вводим пароль если авторизация стоит md5CREATE DATABASE replica_test_ok; -
Смотрим результат на слейве
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.
-
Для наглядности создадим на мастере новую базу
sudo su postgres
psql
CREATE DATABASE failover_s1_to_s2_test_ok;
\q
exit
-
Выключаем мастер
sudo service postgresql stop
#или если хочется прям ваще по жести то вместо остановки постгреса убьем весь серверsudo shutdown -h now
-
Проверяем слейв 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
Видим отказ, т.к. слейв еще не знает что мастер умер
-
Создаем триггер файл и превращаем ag-psql10-s2 в новый мастер
Помним что в recovery.conf триггер файлом мы указали файл «/tmp/to_master»
Создаем этот файл# Не имеет значения авторизованы вы под postgres или под какой либо другой учеткой.# В данном случае я выполняю команду из под postgrestouch /tmp/to_master
Пытаемся снова создать базу
postgres=# CREATE DATABASE failover_s1_to_s2_complete;
CREATE DATABASE
Видим что база успешно создана. Мастер умер! Даздравствует новый Мастер! В этот момент клиенты уже могут набигать на новый мастер
-
Переключаем клиентские приложения на новый мастер
- Я предпочитаю менять DNS запись. У меня есть отдельное имя psql_master где прописан айпишник текущего мастера
- Можно поменять айпиадрес мастера
- Или поменять в приложениях настройки подключений со старого мастера на новый
- А лучше поднять специальный балансировщик и настраивать все подключения на него, а он уже автоматом будет перенаправлять запросы на действующего мастера
на вкус и цвет, я ленивый пользуюсь первым способом но ищу в себе силы поднять 4й способ. Способы 2 и 3 для тех кто любит знатно подрочить.
-
-
PostgreSQL 10 — Потоковая репликация — Превращаем старый мастер ag-psql10-s1 в слейв
После того как мы перенесли роль мастера на ag-psql10-s2, наш почивший мастер ag-psql10-s1 не в курсе последних событий, и как только он стартанет — он начнет активно принимать подключения и писать в себя данные. Ну а клиентам плевать куда писать, им куда дадут они туда и пишут. Поэтому если часть клиентов уже пишет на s2, а часть например еще не в курсе что в сети новый хозяин, в случае пробуждения пребывающего в таком же неведнии s1, мы рискуем получить в сети 2 мастера. Этим и хорош способ со сменой адреса DNS имени, что клиент сам не подозревая переключится на новый мастер. В любом случае сразу же после включения нам надо вырубить постгрес на старом мастере
sudo service postgresql stop, а дальше тихо мирно продолжать конфигурировать его в новый слейв.-
Стераем директорию 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'
-
Запускаем новый слейв ag-psql10-s1
service postgresql start
-
Проверяем что он в режиме READONLY
psql
postgres=# create database qwe;
ОШИБКА: в транзакции в режиме "только чтение" нельзя выполнить CREATE DATABASE
-
На текущем мастере ag-psql10-s2 создаем тестовую БД
postgres=# CREATE DATABASE master_to_slave_config_ok;
CREATE DATABASE
-
Смотрим результат на слейве
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.
- Убиваем мастер s2 в случае если он сам не умер
- Создаём на слейве s1 триггер файл:
. Слейв становится мастером. Можно проверить что он начал принимать команды записи.
touch /tmp/to_master
- Переподключаем клиенты на новый мастер s1
- Запускаем старый мастер s2 и выключаем на нем postgresql если запущена
sudo service postgresql stop
- Удаляем старую базу
sudo su postgres
rm -R /var/lib/postgresql/10/main/
- Закачиваем новую базу
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)
- Удаляем recovery.done
rm /var/lib/postgresql/10/main/recovery.done
- Добавляем в 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'
- Запускаем текущий слев
service postgresql start
- По окончании имеем исходный вариант работы.
Собственно вот и все дела. Если есть какие-то вопросы — не стесняйтесь задавать их в комментариях.
P.S. Лучше обкатать 2 фейловера, с мастера на слейв с полной передачей ролей и обратно. Делается это за тем, чтобы проверить все конфиги в контролируемой среде. До того, как что-то реально сломается.
-
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.