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
То при вводе команды
psql
система попросит вас ввести пароль вашего пользователя postgres в postgresql. У меня он h4GiQn. Если у вас просит пароль, но вы не помните его, надо изменить md5 на trust, перезапустить постгрес и вас пустит без пароля. -
Бэкапим pg_hba.conf
#будучи всё еще авторизованными под пользователем postgres cp /etc/postgresql/10/main/pg_hba.conf /etc/postgresql/10/main/pg_hba.bkp
-
Редактируем 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 -
Бэкапим postgresql.conf
#будучи всё еще авторизованными под пользователем postgres cp /etc/postgresql/10/main/postgresql.conf /etc/postgresql/10/main/postgresql.bkp
-
Редактируем 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.
- listen_addresses
-
Перезапускаем postgres
#будучи всё еще авторизованными под пользователем postgres service postgresql restart #система попросит ввести пароль вашей админской учетки exit
-
-
PostgreSQL 10 — Потоковая репликация — Настраиваем слейв
-
Останавливаем postgresql
sudo su postgres service postgresql stop #система попросит ввести пароль вашей админской учетки
-
Удаляем текущие данные
#будучи всё еще авторизованными под пользователем postgres rm -R /var/lib/postgresql/10/main/
Для того чтобы инициализировать репликацию, необходимо скачать с сервера свежую копию данных. Иначе если разрыв данных будет слишком велик (больше чем доступно данных согласно wal_keep_segments), репликация попросту не запустится.
-
Закачиваем данные с мастера
#будучи всё еще авторизованными под пользователем 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.
Дожидаемся окончания загрузки. -
Настраиваем 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.
-
Приводим раздел репликации СЛЕЙВА к такому виду:
#будучи всё еще авторизованными под пользователем 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
-
Запускаем слейв
#будучи всё еще авторизованными под пользователем postgres service postgresql start
-
-
PostgreSQL 10 — Потоковая репликация — Проверяем репликацию
-
Создаем на мастере тестовую базу данных
sudo su postgres #Если вдруг мы авторизованы под другим пользователем psql #Запускаем psql, вводим пароль если авторизация стоит md5 CREATE 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 или под какой либо другой учеткой. # В данном случае я выполняю команду из под postgres touch /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 фейловера, с мастера на слейв с полной передачей ролей и обратно. Делается это за тем, чтобы проверить все конфиги в контролируемой среде. До того, как что-то реально сломается.
24 комментария
все круто, спасибо!
Я жду уже час
Что не работает?
Здраствуйте!
Как с вами связаться?
написать на admin@adminguide.ru
Какова должна быть конфигурация Postgresql.conf? Если у нас был безвозвратно потерян мастер, на slave у нас конфигурация без wal_level=replica и прочего. Если мы добавляем прошлый master как slave надо ли ему прописывать настройки так как было, когда он был
master? И где после failover’ов должны быть прописаны настройки postgresql.conf?
Нет особого смысла привязываться к былому статусу серверов, кто из них был мастером а кто слейвом. В результате тех или иных событий мастер упал, роль мастера взял слейв. То есть на данный момент в сети присутвствует один сломанный сервер и один мастер.
Просто пробегаем по статье с самого начала и конфигурируем новый мастер для отдачи реплики
Чиним\заменяем второй сервер, настраиваем его как слейв, выкачиваем реплику
Смотрим что всё работает, репликация идёт, радуемся.
Если же например новый слейв мощнее мастера, руководствуясь статьей отрабатываем фейловер чтобы поменять роли и направление репликации. Снова радуемся.
Я бы отработал фейловер несколько раз туда обратно чтобы быть уверенным что всё работает. СТатья как раз писалась чтобы прямо по ней можно было выполнить всё по пунктам и получить в результате два сервера готовых к смене ролей в любой момент.
Меня просто интересовало, что конфиг postgresql с параметрами репликации надо прописывать на вновь вернувшемся сервере или на текущем мастере, но как я понял из вашего ответа можно сконфигурировать на вновь вернувшемся ,только в начале его запустить в режиме slave, а потом уже переключать или не переключать в зависимости от надобности и желания. Спасибо за ответ.
В общем статья конечно хорошая, вот только автор совсем забыл, что большинство будет настраивать на бою, а там в процессе бекапа на слейв будут тикать бинлоги, которые в итоге и будут потеряны на слейве, а это существенная деталь — без остановки бинлога на мастере статья нерабочая!
А можно поточнее о каком именно логе идёт речь? MySQL binlog?
Статья как раз рассматривает вариант создания репликации на горячую.
pg_basebackup при выполнение не будет блокировать таблицы чтоб данные были согласованы ?
Нет, pg_basebackup как раз можно применять на работающих кластерах. Эта команда никак не повлияет на работу других клиентов. Ну разве что на время создания слегка может просесть производительность на слабых серверах
ok, а если база ~10тб, а сеть не очень.host1 временно недоступен, скажем упал на 2 часа, переключили на слейв (host2), переключили — ок, host1 -поднялся, и ждёт lsn из WAL-a предшествующего первому на host2 (select pg_walfile_name(‘1211/C4000000’); 0000000200001211000000C3 а на host2 есть только 0000000200001211000000C4 и больше) как переключить host2 в режим слейва без рукоблудия с pg_base_backup ?
Без рукоблудия — выделить бюджет и дописать своё ПО занимающееся автоматизацией этого вопроса, силами штатных разработчиков. С базой ~10 Тб, сеть должна быть самый минимум 10 гигабитная. Ну и у фирмы если такая база, то без проблем должно найтись миллионов 10-20 на решение этого вопроса силами наёмных разработчиков или покупкой готового решения. Такие масштабы мягко говоря выходят далеко за пределы работающего почти из коробки абсолютно бесплатного опенсорсного решения 🙂
Здравствуйте, не работает слэйв после настройки. Выдает ошибку /var/run/postgresql/.s.psql.5432 does not exist
похоже на ошибку\опечатку в pg_hba.conf, нужно перепроверить как оно там всё.
Опытным путем было установлено, что ошибка появляется после использования команды pg_basebackup. После этого по пути /var/run/postgresql/ пропадают файлы, которые там были до pg_basebackup
pg_basebackup засасывает все данные с мастера, необходимо тогда смотреть что с мастером. С него должна приезжать рабочая копия мастера.
Мастер работает отлично. Версия на обоих одинаковая. Настроен был по вашей инструкции.
Воспроизвел такую ошибку. На слэйве в postgres.conf закомментировал сначала параметр #hot_standby = on, после перезапуска postgresql.service при запуске psql возникает аналогичная ошибка и postgresql не слушает порт 5432. Вернул параметр на место (убрал комментарий перед hot_standby = on), перезапустил сервис postgresql.service — psql запустился без ошибок, порт 5432 занят postgresql.
Слейв не стартовал, нужно было сделать sudo chown postgres -R /var/lib/postgresql/10/main/
в конце.
Скажите, пожалуйста, а как вы отслеживаете лаги и прочие несогласованности между мастером и слэйвом? И вообще как организовать мониторинг в общем случае?
Добрый день! Не отслеживаю совсем. Если репликация прерывалась на большое время — она останавливается совсем и тогда её нужно перезапускать руками. Если не прерывалась — то в реплике всё 1в1 как в мастере. На то это и реплика. Слейв с мастера тащит wal записи, а не конкретные транзакции.