PostgreSQL / Отказ мастера в PostgreSQL-кластере: как быть?

в 0:11, , рубрики: failover, postgresql, replication, репликация, метки: , , ,

Приветствую. Сегодня я хотел бы поговорить о такой неприятной ситуации, как отказ мастера в случае применения нативной репликации в PostgreSQL 9.x. Итак, предположим, что у вас есть кластер из двух и более PostgreSQL-серверов и на мастер внезапно упал метеорит. Логично предположить, что вам придётся сделать мастером одну из реплик. Сделать это можно двумя способами.
1. Применение триггер-файла.

В мануале по настройке репликации сказано, что в recovery.conf помимо прочего можно(и нужно) указать параметр trigger_file. Здесь всё просто — как только вы создадите на реплике файл, указанный в этом параметре, PostgreSQL прервёт процесс восстановления(в нашем случае — репликации) и откроет новый timeline.
Это значит, что после создания триггер-файла изменится позиция счётчика бинарного лога, причем не последовательно(скажем — с 000000010000000000000043 на 000000010000000000000044), а с указанием новой эпохи — (на 000000020000000000000043).
Хорошая новость — этот способ не потребует рестарта — всё произойдёт налету. Даунтайма не будет(время на изменение конфигов на клиентах в расчёт не берём), все соединения сохранятся — PostgreSQL просто прибьёт процесс walreceiver и даст добро на запись.
Плохая новость заключается в том, что этот способ хорош если у вас только два сервера — мастер и реплика. Проблема заключается в том, что в случае, если кластер состоит из 3х и более машин — сделать эту ноду новым мастером без переналивки реплик не получится — при попытке привязать другую реплику к новому мастеру, PostgreSQL неизменно говорит следующее:FATAL: timeline 2 of the primary does not match recovery target timeline 1
Всяческие попытки подсунуть репликам history-файл(который хранит в себе точку перехода на новый timeline — этот файл создаётся каждый раз по завершению процесса восстановления) успехом так же не увенчались. В общем-то участники официального MailList`а придерживаются такой же точки зрения — при таком подходе другие реплики придётся переналить(в случае с 9.0 — используя pg_start_backup/pg_stop_backup и rsync, а в случае с 9.1 — используя утилиту pg_basebackup).
2. Удаление recovery.conf

Почему-то описание второго способа в мануалах найти не удалось(возможно, он там есть и я был недостаточно внимателен — утверждать не буду). Думаю, вы согласитесь, что он прост, логичен и, видимо, надежен(по крайней мере — мне так и не удалось что-либо окончательно сломать в процессе многократных экспериментов):
1. Из всего кластера вам нужно найти самую свежую реплику. Сделать это можно из консоли, выполнив на каждом хосте нечто вида:# ps aux|grep postg|grep rec
postgres 143 0.0 13.2 8692004 6533448 ? Ss Feb06 3:58 postgres: startup process recovering 00000001000001E500000054
postgres 2683 0.0 0.0 8699452 4044 ? Ss Feb09 0:33 postgres: wal receiver process streaming 1E5/542F9970
Если метеорит на ваш мастер еще не упал, но вы этого ожидаете с минуты на минуту — мастер-ноду лучше потушить заранее, дабы за время ваших манипуляций, позиции бинарного лога не менялись.
2. На выбранной реплике меняем postgresql.conf таким образом, чтобы нода смогла быть мастером(ниже приведенные параметры взяты из мануала по настройке репликации, в вашем случае значения, разумеется, могут отличаться):wal_level = hot_standby
max_wal_senders = 5
wal_keep_segments = 32
archive_mode = on
archive_command = 'cp %p /path_to/archive/%f'
3. Правим pg_hba.conf:host replication postgres 192.168.100.3/32 trust
4. Удаляем recovery.conf
5. Делаем рестарт PostgreSQL на новом мастере.
6. Правим recovery.conf на остальных репликах(указываем нового мастера) и выполняем рестарты.
Таким вот нехитрым способом можно превратить реплику в мастер, не теряя позицию бинарного лога. Из очевидных минусов — придётся рестартить весь кластер(хотя, если у вас есть возможность перевесить IP-адрес со старого мастера на новый — рестарт реплик не потребуется).
Если вы по каким-то причинам хотите сделать новым мастером реплику, позиция бин-лога, которой не является самой новой — можно перекинуть нужные файлы из директории pg_xlog(предварительно потушив PostgreSQL на обоих машинах и на всякий случай отложив замещаемые файлы в сторону). К сожалению, этот кейс(конечно же, имеется ввиду назначение мастером отстающей реплики, а не второй раздел поста целиком) я еще не успел протестировать, но подозреваю, что никаких проблем в этом месте возникнуть не должно.
В общем-то, в процессе экспериментов, единственное проблемное место, которое удалось нащупать — ситуация, когда какая-то из реплики отстала настолько, что на новом мастере уже нет необходимых ей XLOG-файлов. Как с этим бороться я рассказывал в своём предыдущем посте — могу добавить лишь то, что если вы при архивации пересылаете бинарные логи на бэкапный-сервер — эту проблему вряд ли можно будет назвать существенной.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js