Pull to refresh

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

PostgreSQL
Приветствую. Сегодня я хотел бы поговорить о такой неприятной ситуации, как отказ мастера в случае применения нативной репликации в 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-адрес со старого мастера на новый — рестарт реплик не потребуется).

Если вы по каким-то причинам хотите сделать новым мастером реплику, позиция бин-лога, которой не является самой новой — придётся сначала назначить мастером самую новую реплику(желательно закрыть её от случайных соединений на запись), синхронизировать её с той репликой, из которой вы хотите в итоге сделать мастер и только после этого делать на ней все операции описанные выше(то есть по сути — вы назначите мастер дважды — сначала только для одной реплики, а потом уже для всех остальных).

В общем-то, в процессе экспериментов, единственное проблемное место, которое удалось нащупать — ситуация, когда какая-то из реплики отстала настолько, что на новом мастере уже нет необходимых ей XLOG-файлов. Как с этим бороться я рассказывал в своём предыдущем посте — могу добавить лишь то, что если вы при архивации пересылаете бинарные логи на бэкапный-сервер — эту проблему вряд ли можно будет назвать существенной.
Tags:postgresqlreplicationрепликацияfailover
Hubs: PostgreSQL
Total votes 28: ↑25 and ↓3 +22
Views7.2K

Comments 9

Only those users with full accounts are able to leave comments. Log in, please.

Popular right now