Простите, я сломал ваш recovery.conf

i break you recoveryВ PostgreSQL начиная с очень давних времён аж версии 8.0 вышедшей в далёком 2005 году для восстановления в определённую точку времени использовался специальный файл конфигурации recovery.conf. Этот же файл впоследствии стал использоваться для режима standby и потоковой репликации.

Однако начиная со следующего релиза PostgreSQL 12 больше recovery.conf работать не будет: я его сломал.
Но зачем?
Была у recovery.conf одна особенность: читался он только при старте СУБД. И если для point-in-time recovery который нужен реже чем раз в год с этим смириться ещё можно, то вот необходимость рестарта всей базы для изменения адреса upstream сервера репликации несколько удручает. Видел разные способы извращений для обхода этого ограничения вроде использования L3 роутинга, схемы с каскадными репликациями (чтобы соответственно перезапускать не все реплики, а хотя бы только часть) и даже (хоть в production не встречал) walbouncer.

После очередного планового рестарта реплик только из-за необходимости изменить параметры репликации решил я поковырять, а чего будет стоить научить PostgreSQL перечитывать primary_conninfo по SIGHUP? Оказалось всё плохо. В принципе, необходимо поменять всего одну переменную в startup процессе и оттуда же запросить рестарт WalReceiver — и на этом всё, репликация продолжится с новым адресом корректно. Осталось корректно это реализовать. Несколько недель спустя я закончил патч с реализацией перечитывания recovery.conf по SIGHUP сигналу, при этом тот патч никак не ломал имеющееся поведение базы.

Затем, набравшись смелости, отправил его в список рассылок разработчиков PostgreSQL. На что довольно быстро ответил Michael Paquier:

Before making some of them as reloadable, let’s switch them to be GUCs first and not re-invent the SIGHUP handling of parameters as your patch does.

Упс, оказалось, что я задавал поисковику неправильный вопрос. Спрашивать надо было не про перечитывание recovery.conf, а о превращении параметров из живущего отдельно recovery.conf в инфраструктуру GUC (grand unified configuration), используемую для всех остальных параметров СУБД. То есть однозначно нет, такой патч нам не нужен, такое мы не хотим. Давайте сначала перенесём все эти настройки из recovery.conf в нашу стандартную инфраструктуру настроек.

На этом невесёлом известии я погоревал и подумал: «А вот давайте перенесём!». Почитал архивные обсуждения по правильному поисковому запросу, открыл последнее найденное обсуждение переноса настроек (ссылку любезно предоставил Michael Paquier в своём ответе, за что ему отдельное спасибо, как и за быстрый ответ). На тот момент мая 2018 года патч был заброшен уже больше года. Значит, отсюда и начнём. Или правильнее сказать «продолжим»? По плану развлечения:

  1. прочитать и составить список правок к последней опубликованной версии патча
  2. разобрать изменения в патче и перенести нужное на актуальную версию кодовой базы
  3. исправить все упоминания recovery.conf и его параметров в документации
  4. починить тесты
  5. отправить новый патч в список рассылок
  6. получить какие-нибудь отклики
  7. чего-нибудь поправить согласно пожеланиям и вернуться на пункт 5
  8. получить ещё раз отказ в принятии патча (через годик-полтора)


Похоже на план действий? Ну вот и двигаемся по нему!

Долго ли, коротко ли, добрался до пункта номер пять и 21 июня 2018 года опубликовал новую версию патча, в новой ветке обсуждений. Затем 3 месяца в гнетущей тишине леденящего душу молчания рыбы Баскервилей. На исходе сентября неожиданно к патчу проявляет интерес Peter Eisentraut — один из Core разработчиков с правом коммита. Спустя несколько итераций правок, пока я тихо-мирно уехал на несколько дней погулять-посмотреть Будапешт и осматриваю достопримечательности, вдруг приходит обескураживающее письмо от Peter Eisentraut:

I went over the patch and did a bunch of small refinements. I have also updated the documentation more extensively. The attached patch is committable to me.

То есть, Peter Eisentraut поправил ещё некоторые мелочи по своему усмотрению, обновил документацию, сжёг целиком раздел recovery-config.sgml и считает, что в таком виде патч уже можно принимать. Ой, а я думал это случится только для postgresql 13, даже если так очень повезёт, что патч вообще дойдет до состояния готовности к коммиту.

И несколькими днями спустя, а именно 25 ноября этого 2018 года, Peter Eisentraut действительно принимает этот патч:

recovery.conf settings are now set in postgresql.conf (or other GUC sources). Currently, all the affected settings are PGC_POSTMASTER; this could be refined in the future case by case.
Recovery is now initiated by a file recovery.signal. Standby mode is initiated by a file standby.signal. The standby_mode setting is gone. If a recovery.conf file is found, an error is issued.
The trigger_file setting has been renamed to promote_trigger_file as part of the move.
The documentation chapter «Recovery Configuration» has been integrated into «Server Configuration».
pg_basebackup -R now appends settings to postgresql.auto.conf and creates a standby.signal file.
Author: Fujii Masao
Author: Simon Riggs
Author: Abhijit Menon-Sen
Author: Sergei Kornilov

Уже прошло две недели и этот коммит не откатили. Удивительно. И, кажется, даже не собираются. Поразительно. Неизвестно, не решит ли сообщество поменять поведение в какую-нибудь сторону ещё раз, тем более до feature freeze релиза postgresql 12 в апреле ещё есть немного времени. Но, похоже, больше recovery.conf всё-таки у нас не будет.

Так что же изменилось


Сперва-наперво, СУБД откажется стартовать, если найдёт recovery.conf файл — это было сделано специально, чтобы пользователь воспользовавшись одной из множества старых инструкций не удивлялся, почему база игнорирует конфигурацию в этом файле.

Старая настройка standby_mode пропала. Теперь её, равно и как сам факт наличия recovery.conf для включения режима восстановления, заменяют два файла (любого содержания, обычно пустые):

  • $PGDATA/recovery.signal — идеалогический наследник standby_mode=off, восстановление из архива будет произведено до указанной в конфигах точки;
  • $PGDATA/standby.signal — соответственно, standby_mode=on. Этот файлик мы будем видеть на всех репликах


Если startup процесс базы нашёл оба файла — то считаем что мы в режиме standby.

Если для ясности свести изменения параметров в табличку:

old recovery.conf
PostgreSQL 12+ postgresql.conf
primary_conninfo
primary_conninfo
primary_slot_name
primary_slot_name
trigger_file
promote_trigger_file
recovery_min_apply_delay
recovery_min_apply_delay
recovery_target
recovery_target
recovery_target_name
recovery_target_name
recovery_target_time
recovery_target_time
recovery_target_xid
recovery_target_xid
recovery_target_lsn
recovery_target_lsn
recovery_target_inclusive
recovery_target_inclusive
recovery_target_timeline
recovery_target_timeline
recovery_target_action
recovery_target_action
restore_command
restore_command
archive_cleanup_command
archive_cleanup_command
recovery_end_command
recovery_end_command


То можно заметить, что изменено чуть меньше чем ничего. На данный момент (за единственным исключением префикса promote_ для promote_trigger_file) все новые параметры называются точно так же как и старые и принимают те же самые возможные значения. Хотя на самом деле есть ещё изменение касательно настроек цели для восстановления. Не знаю, пользовался ли этим кто-то раньше, но это было задокументированное поведение и можно было указать одновременно несколько recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time или recovery_target_xid. Например,

recovery_target_lsn = '1/1D9FEA00'
recovery_target_xid = '5238954'


Реально использовалась для восстановления последняя строка из recovery.conf. Больше так нельзя, цель для восстановления должна быть указана максимум одна. Впрочем, из-за логики инфраструктуры GUC по-прежнему можно указать одноимённый параметр несколько раз:

recovery_target_lsn = '1/1D9FEA00'
recovery_target_lsn = '1/16AC7D0'


Такое допустимо, восстанавливаться будем до значения настройки указанной последней.

И, в общем-то, это всё что следует сказать об изменениях видимых снаружи PostgreSQL. pg_basebackup -R (--write-recovery-conf) остался на своём месте и делает то что и предназначен, лишь только теперь он вместо recovery.conf добавит параметры в postgresql.auto.conf и создаст файл standby.signal

К сожалению, говоря о том, что это все видимые в данный момент изменения я именно это и имею в виду. Все новые параметры по-прежнему установлены как PGC_POSTMASTER, то есть могут быть изменены только при старте PostgreSQL. Как уже упоминалось, это было требование со стороны сообщества разработчиков: сначала перенести все настройки, и только потом уже смотреть, можно ли их менять на запущенной базе. Так что сейчас PostgreSQL в замечательной стадии разработки, когда старое поведение уже сломали, а изменений к лучшему ещё не завезли.

Я уже опубликовал патч который разрешит менять primary_conninfo и primary_slot_name налету. Посмотрим, что из этого получится.

Простите, я сломал ваш recovery.conf

© Habrahabr.ru