Введение в PostgreSQL BDR

    Введение в PostgreSQL BDR


    image
    PostgreSQL это не только стабильная и надежная СУБД но и плюс ко всем это динамично развивающийся продукт, в котором от релиза к релизу появляются самые разные прорывные вещи. В свое время одной из таких технологий была потоковая репликация. Это высокопроизводительная репликация которая позволяет очень легко и дешево масштабировать базу данных на чтение. Используя ее можно создавать надежные конфигурации распределяя нагрузку на чтение между узлами. Однако как я написал выше, продукт развивается, и сегодня в статье речь пойдет о новой технологии BDR (Bi-Directional Replication).

    Немного терминов для тех кто не в теме:
    WAL (Write Ahead Log) — журнал транзакции, на нем основана встроенная потоковая репликация в постгресе, СУБД пишет туда все что происходит с данными в БД.
    SR (Streaming Replication) — общее название встроенной потоковой репликации которая которая основана на WAL, все что пишется в WAL, затем отправляется на слейвы и воспроизводится. Бывает физическая и логическая потоковая репликация.
    PLSR (Physical Log Streaming Replication) — физическая потоковая репликация (то что уже реализовано и работает), все что попало в WAL без последующего разбора реплицируется на слейв сервера, это и изменение данных/схемы и более низкоуровневые вещи (full page writes, vacuum, hint bit settings).
    LLSR (Logical Log Streaming Replication) — логическая потоковая репликация (появится в 9.4) также основана на WAL журналах, но уже более интеллектуальная и для репликации извлекается только определенная часть журналов в которых описываются изменения схемы и данных БД (то есть некоторые низкоуровневые вещи отсеиваются).

    Что скрывается под термином BDR?
    BDR (Bi-Directional Replication) это новая функциональность добавленая в ядро PostgreSQL которая предоставляет расширенные средства для репликации. На данный момент это реализовано в виде небольшого патча и модуля. Заявлено что полностью будет только в PostgreSQL 9.5 (сейчас 9.3-stable и 9.4-beta1).

    Если коротко, то BDR позволяет создавать географически распределенные асинхронные мульти-мастер конфигурации (о да, детка) используя для этого встроенную логическую потоковую репликацию LLSR.

    Тем не менее, BDR не является инструментом для кластеризации, т.к. здесь нет каких-либо глобальных менеджеров блокировок или координаторов транзакций (привет Postgres-XC/XL). Каждый узел не зависит от других, что было бы невозможно в случае использования менеджеров блокировки. Каждый из узлов содержит локальную копию данных идентичную данным на других узлах. Запросы также выполняются только локально (чтобы было более понятно о чем речь, приведу сравнение с Postgres-XC/Postgres-XL, там все серверы работают как бы в одной упряжке, транзакции рулятся глобальным менеджером транзакции, а запросы от приложения поступают на координатора(ов) который отправляет выполняться пришедшие запросы на любой рабочий узел, вот). При этом каждый из узлов внутренне консистентен в любое время, целиком же группа серверов является согласованной в конечном счете (eventually consistent).

    Уникальность BDR заключается в том что она непохожа ни на встроенную потоковую репликацию, ни на существующие trigger-based решения (Londiste, Slony, Bucardo).

    Самым заметным отличием от потоковой репликации является то, что BDR (LLSR) оперирует базами (per-database replication), а классическая PLSR реплицирует целиком инстанс (per-cluster replication), т.е. все базы внутри инстанса.

    Существующие ограничения и особенности:
    1. Все изменения данных вызываемые INSERT/DELETE/UPDATE реплицируются (TRUNCATE на момент написания статьи пока не реализован)
    2. Большинство операции изменения схемы (DDL) реплицируются успешно. Неподдерживаемые DDL фиксируются модулем репликации и отклоняются с выдачей ошибкой (на момент написания статьи не работал CREATE TABLE… AS)
    3. Определения таблиц, типов, расширений и т.п. должны быть идентичными между upstream и downstream мастерами.
    4. Действия которые отражаются в WAL, но непредставляются в виде логических изменений не реплицируются на другой узел (запись полных страниц, вакуумация таблиц и т.п.). Таким образом логическая потоковая репликация (LLSR) избавлена от некоторой части накладных расходов которые присутствуют в физической потоковой репликации PLSR (тем не менее это не означает что LLSR требуется меньшая пропускная способность сети чем для PLSR).

    Итак пожалуй хватит теории, немного практики. Уже сейчас есть возможность потестировать Bi-Directional репликацию.

    Установка выполняется на двух виртуальных машинах с CentOS 6.5 minimal. Устанавливаем необходимые для сборки пакеты:

    # yum install readline-devel zlib-devel yum-utils -y
    # yum groupinstall "Development Tools" -y
    


    Переходим в аккаунт postgres и выполняем установку postgresql с поддержкой BDR. Тут стоит отметить что парни из 2ndQuadrant написали установщик чтобы желающие попробовать не прилагали больших усилий по установке и настройке, за что им пучок зелени.

    # su - postgres
    $ curl -s "http://git.postgresql.org/gitweb/?p=2ndquadrant_bdr.git;a=blob_plain;f=contrib/bdr/scripts/bdr_quickstart.sh;hb=refs/heads/bdr-next" | bash
    


    Добавляем каталог с исполняемыми файлами postgres в переменную окружения PATH и тут же проверяем на psql. Кто не знает, команда export одноразовая, поэтому если вы планируете долго использовать или играться с BDR, то добавьте эту команду в .bashrc вашего пользователя (если у вас bash конечно же).

    $ export PATH=$HOME/2ndquadrant_bdr/bdr/bin:$PATH
    $ psql --version
    psql (PostgreSQL) 9.4beta1_bdr0601
    


    Инициализируем каталоги баз данных на обоих узлах после чего сразу же запускаем. Предварительно править postgresql.conf необязательно, при первом запуске мы создадим тестовую базу которая и будет в дальнейшем реплицироваться.

    $ initdb -D data/ -A trust -U postgres
    $ pg_ctl -l logfile -D data/ -w start
    $ psql -c 'create database staging_db'
    


    Создали базу, после чего переходим к настройке postgresql.conf. Сначала настраиваем upstream мастер. В конфигурации ниже, мы указываем необходимость загрузки библиотеки bdr (shared_preload_libraries), определяем уровень подробности WAL журналов в значение logical (wal_level), определяем количество слотов для репликации, максимально возможное количество процессов занятых в отправке WAL журналов (wal_senders) и включаем трекинг времени для операции COMMIT что необходимо для разрешения конфликтов (last-UPDATE-wins). Затем в конце файла определяем конфигурацию для BDR: указываем название соединения и настройки для подключения к удаленному узлу. Стоит отметить, что имя указываемое в bdr.connections является произвольным (у меня это имя виртуальной машины), главное что указанное имя должно участвовать в именах нижележащих параметров.

    $ vi data/postgresql.conf
    listen_address = '*'
    shared_preload_libraries = 'bdr'
    wal_level = logical
    wal_senders = 4
    max_replication_slots = 4
    track_commit_timestamp = on
    bdr.connections = 'vm13'
    bdr.vm13_dsn = 'host=192.168.122.13 port=5432 user=postgres dbname=staging_db'
    


    Теперь конфигурация downstream мастера. Сначала привожу описание конфигурации и затем ее разбор ниже.

    $ vi data/postgresql.conf
    listen_address = '*'
    shared_preload_libraries = 'bdr'
    wal_level = logical
    wal_senders = 4
    max_replication_slots = 4
    track_commit_timestamp = on
    bdr.connections = 'vm12'
    bdr.vm12_dsn = 'host=192.168.122.12 port=5432 user=postgres dbname=staging_db'
    bdr.vm12_init_replica = on
    bdr.vm12_replica_local_dsn = 'host=127.0.0.1 port=5432 user=postgres dbname=staging_db'
    


    Настройка второго узла отличается немногим, в частности здесь в конфигурации BDR мы указываем необходимость выполнить инициализацию реплики (bdr.vm12_init_replica) с узла указанного в bdr.vm12_dsn на локальную базу чьи реквизиты указаны в bdr.vm12_replica_local_dsn. Последний параметр является обязательным в случае если кластер БД инициализрован с помощью initdb (как раз наш случай) и в таком случае в кластере должна существовать пустая база которая будет в дальнейшем участвовать в репликации.

    В случае инициализации через pg_basebackup опция bdr.vm12_replica_local_dsn не нужна.

    Теперь определяем настройки аутентификации на обоих узлах, в моем случае все разрешено. Для production инсталяции так конечно же делать нельзя.

    $ vi data/pg_hba.conf
    host    all             all             192.168.122.0/24        trust
    host    replication     postgres        192.168.122.0/24        trust
    

    Выполняем перезапуск обоих узлов и смотрим журналы
    $ pg_ctl -l logfile -D data/ -w restart
    


    upstream мастер:
    vm12 ~ $ tail -f logfile
    LOG: unexpected EOF on standby connection
    LOG: starting logical decoding for slot bdr_16384_6029905891437956874_1_16384__
    DETAIL: streaming transactions committing after 0/1898F90, reading WAL from 0/1898C30
    LOG: logical decoding found consistent point at 0/1898C30
    DETAIL: running xacts with xcnt == 0
    LOG: starting background worker process «bdr (6029905879776466735,1,16384,): vm13: apply»

    downstream мастер:
    vm13 ~ $ tail -f logfile
    LOG: registering background worker «bdr (6029905891437956874,1,16384,): vm12: apply»
    LOG: starting background worker process «bdr (6029905891437956874,1,16384,): vm12: apply»
    LOG: logical decoding found consistent point at 0/18A4290
    DETAIL: running xacts with xcnt == 0
    LOG: exported logical decoding snapshot: «0000071B-1» with 0 xids
    LOG: starting logical decoding for slot bdr_16384_6029905879776466735_1_16384__
    DETAIL: streaming transactions committing after 0/18A42C8, reading WAL from 0/18A4290
    LOG: logical decoding found consistent point at 0/18A4290
    DETAIL: running xacts with xcnt == 0


    В журналах все хорошо и ERROR сообщений нет (а если есть, проверяйте конфиги или грешите на разработчиков))). На этом настройка и запуск завершен. Теперь можно проверить работу через создание таблиц в обеих базах.

    Еще пара моментов. Временная остановка репликации осуществляется выключением downstream мастера. Однако стоит отметить что остановленная реплика приводит к тому что upstream мастер продолжит накапливать WAL журналы что в свою очередь может привести к неконтролируемому расходу пространства на диске. Поэтому крайне не рекомендуется надолго выключать реплику.
    Удаление реплики навсегда осуществляется через удаление конфигурации BDR на downstream сервере с последующим перезапуском downstream мастера. Затем нужно удалить соответствующий слот репликации на upstream мастере с помощью функции pg_drop_replication_slot('slotname'). Доступные слоты можно просмотреть с помощью функции pg_get_replication_slots().

    В качестве заключения скажу свои впечатления… У меня конечно есть некоторые вопросы по эксплуатации BDR, ответы на которые, скорей всего придется выяснять опытно-экспериментальным путем. Но уже на данном этапе мне нравится этот новый инструмент, настраивается оно легко и быстро, плюс к этому оно уже работает несмотря на то, что официально появится только в 9.5 (а это примерно через год). Таким образом, с релизом добавится еще один инструмент с помощью которого можно будет создавать надежные отказоустойчивые конфигурации, и это прекрасно. PostgreSQL от релиза к релизу становится только лучше и лучше.

    Собственно на этом все. Всем спасибо за внимание.

    P.S. Ссылки на почитать:
    BDR User Guide
    Logical Log Streaming Replication
    PostgreSQL WAL Shipping and Streaming Replication
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 16
    • +2
      Действительно очень полезная фича. Если будет работать стабильно и прозрачно(понятное и четко описание поведение при различные ситуациях), то это очень классная вещь. PoostgreSQL действительно радует.

      Активно пользуемся этой БД уже более 7 лет. Надо сказать, за это время с базой проблеме вообще не было. Все очень стабильно и надежно.
      • 0
        Какие объёмы и нагрузка, если не секрет?
        • 0
          Ну вот мы работаем лет 10 с PostgreSQL.
          Объемы в разных конфигурациях от 10Гб до 600Гб на один кластер баз данных и таких несколько десятков…
          Нагрузка от десятка то нескольких сотен активных подключений 20% которых пишущие.
          Нам очень нравится, особых проблем за это время не испытывали…
          Единственно — были заморочки, когда места на серверах заканчивались под базу во время большого количества транзакций… тогда рушились некоторые страницы в больших постоянно обновляемых табличках.
      • 0
        Интересно, расскажут ли об этом на грядущей PG Day?…
        • 0
          Крайне скептически отношусь к мультимастер репликации… Особенно. когда к этому добавляют «географически распределенные». Но надеюсь что у разработчиков получится сделать элегантное решение.
          Как планируют разруливать конфликты и бороться со сплитбрейном?
          • 0
            Я так понял что конфликты разрешаются на основе временных меток транзакций, кроме того можно определять свои обработчики конфликтов (страничка в вики). Про split-brain самому интересно, но увы официальной позиции разработчиков по этому вопросу я не нашел.
          • 0
            Пробую. В новой версии, как оказалось, настройка делается не через postgresql.conf, а путем вызова sql функций, что позволяет добавлять/убирать ноды без перезапуска. bdr-project.org/docs/0.9/release-0.9.0.html
            • 0
              да, проект еще не достаточно mature поэтому многое еще может и будет меняться.
            • 0
              Как считаете, для Production окружения можно использовать BDR (ведь PostgreSQL 9.5 уже не за горами) или всё же лучше пока остановится скажем на pgPool-II?
              • 0
                Для production окружения использовать BDR не стоит. Лучше использовать проверенные временем решения как pgpool.
              • 0
                Я так понял, несмотря на позитивные прогнозы, в ядро 9.5 BDR не добавили?
              • +1
                Имеется два географически разнесённых автономных кластера Postgresql-XL. Есть необходимость между ними сделать асинхронную репликацию. При этом клиенты только читают и ходят каждый на свой XL. Тот агент, который пишет — только один и он пишет данные в оба кластера с учётом асинхронной репликации данных. Подскажите, пожалуйста, целесообразно ли для целей репликации использовать PostgreSQL BDR в таком случае? И возможно ли это вообще?
                • +1
                  Извините, не удержусь от того, чтобы ответить вопросом на вопрос. Для вас Postgres-XL – это теоретическая возможность или вы его уже используете в продакшене? Если да, то какую версию?
                  • 0
                    Весь проект находится на стадии разработки архитектуры. Тестируем на виртуалках XL9_5_STABLE. Пока нареканий нет. От всех синтетических тестов получаем предсказуемый и полностью удовлетворительный результат. В продакшн планируем именно такую связку:
                    XL <---BDR-->XL но с окончательным решением определились только к XL.
                  • 0
                    На мой вопрос ответили на «Toster»

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