Отказ мастера в 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-файлов. Как с этим бороться я рассказывал в своём предыдущем посте — могу добавить лишь то, что если вы при архивации пересылаете бинарные логи на бэкапный-сервер — эту проблему вряд ли можно будет назвать существенной.

    Комментарии 9

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

        Я с этим экспериментировал и мне не удалось вторым способ восстановить работу слэйвов без перезаливки базы.
          0
          Не могли бы вы рассказать в чём именно заключалась проблема — я постараюсь её воспроизвести? Дело в том, что переключение со смещенной позицией(когда есть отстающие реплики) я тоже, разумеется, рассматривал — все отработало штатно. В моём случае я тестировался так:
          1. Из /dev/urandom в 5-6 потоков льются данные в одну из таблиц.
          2. Я закрываю мастер фаерволлом от одной из реплик(дабы спровоцировать отставание), жду пару минут — делал и с этим пунктом и без него.
          3. Выключаю мастер.
          4. Делаю описанное выше.

          Более того, мне известен случай, когда случай, когда подобным образом неоднократно переключали production-кластер. Успешно, разумеется.
            0
            Если на будущем мастере смещение будет более ранним чем на одном из слэйвов, то слэйв к нему не подключится.
              0
              Я не просто так писал о необходимости найти самую свежую реплику в начале второй части поста. Или я вас неправильно понял?

              Касательно предпоследнего абзаца(про перемещение файлов xlog`а между машинами) — да, каюсь, не сработало — исправил на работающий вариант.
                0
                Хотя да, точно. Сначала не совсем понял зачем это вам надо было. А так да — вполне может сработать.
          +1
            0
            Изучу, спасибо
            0
            спасибо за статью.

            скорее всего первый пункт и не нужен. можно брать любую из реплик в качесте мастера, нужно лиш вычитсить pg_xlog с остальных.

            www.sql.ru/forum/actualthread.aspx?tid=933852

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое