6
июня
12

Настройка потоковой репликации в PostgreSQL 9



В версии PostgreSQL 8.3 и позже уже был доступен Warm Standby (теплый резерв), использующий PITR (Point-In-Time Recovery, появившийся в 8.0) также называемый «log shipping» (пересылка логов), когда транзакционные логи асинхронно копировались с ведущего узла и сохранялись на ведомом, а затем сразу проигрывались/применялись. Таким образом всегда была копия ведущего сервера при его останове, но пользоваться при Warm Standby ведомым сервером нельзя и он постоянно находился в режиме восстановления (in «recovery mode»).

Hot Standby (горячий резерв) идентичен Warm Standby, но ведомый сервер стал доступен для чтения (read-only), что является огромным преимуществом и дает возможность реализовать балансировку нагрузки запросов от приложения, при этом не оказывая никакой нагрузки на ведущий сервер. При данном способе транзакционные логи (по умолчанию размером 16MB) копируются через сеть в требуемое место (например, с помощью SFTP), а после этого происходит запись/обновление информации в базе на ведомом сервере. Конечно же, выполнение всех этих действий дает некоторые задержки актуализации данных на подчиненном сервере.

Встроенная потоковая репликация (Streaming Replication), появившаяся в текущем релизе СУБД PostgreSQL 9.0, который вышел в сентябре 2010 года после версии 8.4, усовершенствованна и также реализована с помощью передачи WAL (write-ahead logs, журналов (логов) опережающей записи) с главного (Master/Primary) сервера на подчиненный (Slave/Secondary/Replica). Это асинхронная репликация Master/Slave, когда на ведущий/главный сервер идут запросы, приводящие к изменениям в БД, а на подчиненном сервере эти изменения будут выполнены только через некоторое время. В данном случае реализация состоит в том, что создается сетевое подключение между Standby и Master СУБД вместо копирования журналов по 16 мегабайт, как при Warm Standby и Hot Standby. Можно также совмещать Hot Standby и Streaming Replication. Это позволяет увидеть на слейве почти мгновенно изменения, выполненные на мастере. Хотя и при работе только потоковой репликации записи с WAL-логов восспроизводятся сразу же при процессе их получения. При потоковой репликации на серверах создаются специальных два дополнительных процесса walsender и walreceiver на каждую пару серверов управления базами данных, взаимодействующих между собой через сеть. Потоковая репликация позволяет легко реализовать работу нескольких ведомых серверов для одного ведущего, при этом ведомые узлы работают в режиме «только для чтения». На данный момент доступна только асинхронная репликация. Возможность синхронной репликации, когда все изменения происходят в СУБД одновременно, будет доступна с выходом PostgreSQL 9.1, который планируется приблизительно летом 2011г.

Следует сразу отметить некоторые ограничения присущие потоковой бинарной репликации:

— нет возможности реплицировать определенные базы\таблицы, создается точная копия инстанса/кластера СУБД;
— на взаимодействующих между собой серверах, где установлена PostgreSQL, должна быть одинаковая версия операционной системы и СУБД;
— пользователь на главном сервере, использующийся для процесса репликации, должен обладать правами суперпользователя;
— репликацию мульти-мастер реализовать технически невозможно;
— асинхронный механизм, приводящий к некоторому отставанию слейва.

Самым простым методом «поднятия» встроенной репликации между серверами является использование бекапа уровня файловой системы. Это остановка СУБД на ведущем хосте, дальнейшее копирование/архивирование директории данных, разворачивание на ведомом сервере и запуск с нужными настройками в postgresql.conf, pg_hba.conf и recovery.conf. Но данный метод, учитывая тенденции современного мира, не годится для использования на «производстве», так как это приводит к недоступности БД на достаточно длительное время (в зависимости от размеров БД).

Существует еще один метод переноса данных кластера СУБД PostgreSQL на другой сервер для «поднятия» репликации — «онлайн-бекап». При этом не останавливая мастер можно снять снимок директории данных postgresql и в дальнейшем после запуска слейва кластер придет в непротиворечивое состояние используются транзакционные логи (Write-Ahead Log). WAL позволяет также откатывать состояние на произвольный момент времени, если обеспечить постоянное их хранение.

WAL-журналы — это бинарные файлы, создаваемые в своей директории PGDATA/pg_xlog, в которые СУБД пишет образы данных последних модифицирующих запросов к БД. Каждый раз сначала происходит запись в журнал, который гарантированно должен быть записан на диск. Только потом происходит запись в файлы данных базы на диске. После всего вышеописанного транзакция считается завершенной. Учитывая это, после каждой транзакции нет необходимости писать в базу, поскольку запись сначала сохраняется на диск в журнале. Данные из буферов сбрасываются на диск при проходе заданной контрольной точки, а конкретнее — определенного количества записей (default: 3) в журнале либо некоторого интервала времени. Следствием данной методики удаление файлов из pg_xlog может привести к невосстановимому повреждению базы данных. Также, возможно, будет полезным упомянуть, что ни в коем случае не следует ничего удалять из pg_clog — директории, которая содержат журналы метаданных транзакций. Они необходимы для слежения сервером за состоянием транзакций и в случае их случайного удаления база данных окажеться безвозвратно повреждена.

Для возможности создания снимка данных постгреса посылается запрос к серверу от суперпользователя подобного вида: «select pg_start_backup(‘label’,true);», где ‘label’ может быть любым словом. Этот запрос переводит мастер в режим бекапа, при котором можна склонировать директорию данных на слейв (например, с помощью tar, cpio или rsync). Полученный таким образом «snapshot» будет не противоречивый и будет содержать файл, указывающий ведомому серверу когда он был сделан для дальнейшего приведения данных в БД к актуальному состоянию. До посылки на мастере запроса «select pg_stop_backup();» никакие изменения в базу не записываются, а заносятся в транзакционные логи, что стоит учесть и не забывать выйти с данного режима.

Настройка мастера/ведущего сервера

Создаем на мастере пользователя для репликации c разрешенным доступом для подключения через сеть:
— для создания пользователя repl используем запрос:

postgres=# CREATE USER repl SUPERUSER;

— в pg_hba.conf на мастере должна присутствовать запись подобная:

# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
host  replication   repl   192.168.0.2/32      trust 

которая указывает на возможность пользователя repl с IP-адреса 192.168.0.2 не используя пароль подключаться к псевдо базе данных replication.

Далее нужно внести некоторые корректировки в файл postgresql.conf, находящийся в директории данных на мастере:
— указать/проверить прослушиваемый для подключений IP-адрес (по умолчанию только 127.0.0.1), символом ‘*’ указать слушать все имеющиеся интерфейсы на сервере

listen_address = '*' 

— задать тип создаваемых бинарных логов в разделе WRITE AHEAD LOG. В зависимости от этого параметра подчиненный сервер может по разному себя вести: как обычный slave, доступный на чтение, или standby, который по определению является сервером, находящимся в состоянии ожидания данных от ведущего и недоступным для клиентов. По умолчанию, установлено в «minimal», чего достаточно только для восстановления БД после краха самой СУБД. Также доступны значения: «archive», когда подчиненный сервер не доступен для подключений, и «hot_standby», который открывает возможность запросов только на чтение к standby-серверу, что нам и нужно

wal_level = hot_standby 

— в подразделе «Streaming Replication» задать максимальное количество подключений от ведомых серверов, т. е. по сути, планируемое количество слейвов для этого мастера

max_wal_senders = 2 

— минимальное колличество сохраняемых WAL-логов (которые по умолчанию по 16М) в директории pg_xlog на мастере. По умолчанию, установлено в 0, т. е. отключено, что можно оставить, если включено архивирование в доступную для слейва директорию (например, с помощью NFS). Установленное число должно быть таким, чтобы слейв смог восспроизвести изменения, сделанные на мастере в промежуток времени между созданием бекапа кластера и запуска репликации на подчиненном сервере

wal_keep_segments = 32 

— Также можно включить в подразделе «Archiving» архивирование WAL-логов с директории pg_xlog в доступное для слейва хранилище, где он сможет с ними работать (к примеру, в директорию /var/db/archive_xlogs, которую помом монтируем через NFS к слейву, либо с помощью rsync на удаленный сервер). Для директории, куда будут складываться журналы, нужно обеспечить своевременную очистку уже ненужных файлов иначе может закончиться свободное дисковое пространство на данном разделе. Включение архивирования не требуется если wal_keep_segments установлено в достаточно большое значение

archive_mode = on
archive_command = 'cp %p /var/db/archive_xlogs/%f' 

— полезным с точки зрения производительности будет изменить значение контрольной точки, если данные в базе постоянно изменяются, чтобы данные не слишком часто сбрасывались на диск. Для этого можно увеличить количество сегментов в WAL-логе, через которые информация записывается с буфера в базу, что приведет к увеличению занимаемого места транзакционными логами. По умолнчанию, установлено в «3»

checkpoint_segments = 16 

Настройка ведомого/подчиненного сервера

Здесь для начала требуется в подразделе «Standby Servers» конфигурационного файла postgresql.conf установить значение hot_standby = on, что разрешит read-only запросы к СУБД во время процесса восстановления (репликации).
При старте PostgreSQL проверяет наличие файл в директории данных recovery.conf и если он существует, то воспринимает себя слейвом и считывает от туда заданные настройки репликации (пример файла можно найти в /usr/local/share/postgresql/recovery.conf.sample):
— включить режим восстановления и работать как слейв

standby_mode = 'on' 

— прописываем параметры для соединения с мастером

primary_conninfo = 'host= master.pg.sql port=5432 user=repl' 

— задать местонахождения тригер-файла. После появления которого сервер прекращает репликацию и открывается для записи (при этом recovery.conf переименуется в recovery.done и СУБД начинает вести свои WAL-логи), т. е. становится мастером (переходит в режим «чтенье-запись»). Данная возможность служит в качестве файловера («fail over») при выходе из строя главного сервера СУБД. Альтернативным методом создания пустого тригер-файла является удаление или переименование recovery.conf и перезапуск сервера, что, конечно же, менее благоразумно.

trigger_file = '/var/db/pgsql/failover' 

— команда для восстановления WAL-логов мастера с общего хранилища в директорию pg_xlog текущегй СУБД, если архивирование таковых включено на мастере. Замечание: если используется только hot standby без streaming replication, то целесообразно будет использовать утилиту pg_standby, входящую в пакет contrib.

restore_command = 'cp /var/db/archive_xlogs/%f %p' 

— команда используется для очистки журналов, которые больше не нужны слейву. Утилита поставляется в FreeBSD с портом /usr/ports/databases/postgresql90-contrib

archive_cleanup_command = '/usr/local/bin/pg_archivecleanup /var/db/ archive_xlogs %r' 

Далее следует развернуть заранее созданный «онлайн-бекап», не включающий конфигурационных файлов и, возможно, директории с WAL-журналами pg_xlog. После всех проделанных настроек и действий, конечно же, следует перегрузить/запустить демоны СУБД, восспользовавшись утилитой для этого предназначенной pg_ctl или оболочкой для нее в виде rc-скрипта /usr/local/etc/rc.d/postgresql.

Для запуска/перезапуска репликации написал два небольших скрипта для выполнения действий на мастере и слейве соответственно. Перед их запуском следует проверить значения заданных переменных в начале: директория данных posgresql-сервера (здесь — /var/db/pgsql), родительская директория, атрибуты подключения к мастеру.

Первым создается онлайн-бекап данных кластера на мастере, исключив файлы postmaster.log, postmaster.opts, postmaster.pid (можно также каталог pg_xlog, что приведет к восстановлению базы слейва перед началом репликации) и сохраняет этот архив на некотором FTP-сервере.

cat backup_master.sh
#!/bin/sh
PGDATA_DIR="/var/db/pgsql"
PARENT_PGDATA="/var/db"
DATE=`date "+%Y%m%d_%H-%M"`

echo -e "Starting a backup (creates a backup_label file) .."
psql -Upgsql -d postgres -c "SELECT pg_start_backup('base_backup', true)"

echo -e "Backup data directory PostgreSQL $PGDATA_DIR, using tar (and bzip2) - pgsql.$DATE.tar.bz2 ..."
cd $PGDATA_DIR ; 
tar cjf $PARENT_PGDATA/pgsql.$DATE.tar.bz2 --exclude='pg_xlog/*' --exclude='postmaster*' ./* && \
echo -e "`ls -lh $PARENT_PGDATA/pgsql.$DATE.tar.bz2`\n"

echo -e "terminates the backup mode postgresql daemon ...."
psql -Upgsql -d postgres -c "SELECT pg_stop_backup()"

echo -e "Save archive-file on backup-server via FTP ....."
ftp -v -u ftp://backup-server/postgresql/pgsql.$DATE.tar.bz2 $PARENT_PGDATA/pgsql.$DATE.tar.bz2
echo
/usr/local/etc/rc.d/postgresql status
#echo
#ps auxww | grep 'postgres: wal sender process' | grep -v grep 

Второй скрипт скачивает на слейв ахрив, созданный на мастере, и разворачивает в директорию данных СУБД ведомого сервера, сохраняя текущие конфигурационные файлы и потом перед стартом постгреса возвращает их обратно. Главный конфигурационный файл postgresql.conf берется с мастера и sed изменяет значение hot_standby в «on», запуская слейв с этими настройками. Если ранее postgresql-сервер не был запущен, то можна выбрать вначале инициализировать его и установить запускаться при перезагрузке ОС FreeBSD (также будет создан recovery.conf).

cat up_repl_slave.sh
#!/bin/sh
PGDATA_DIR="/var/db/pgsql"
PARENT_PGDATA="/var/db"
master_host="master.pg.sql"
repl_user="repl"
config_dir="/var/db/pgsql_configs"

echo -n "Create a new PostgreSQL database cluster and file recovery.conf in the standby's data directory $PGDATA_DIR? [y/n]:"
read answer
if test $answer = 'y'; then
echo -e "postgresql_enable=\"YES\"\npostgresql_data=\"$PGDATA_DIR\"" >> /etc/rc.conf
mkdir -p $PGDATA_DIR; rm -rf $PGDATA_DIR/*; chown -R pgsql:pgsql $PGDATA_DIR
/usr/local/etc/rc.d/postgresql initdb
echo -e "standby_mode = 'on'\nprimary_conninfo = 'host=$master_host port=5432 user=$repl_user'\ntrigger_file = '$PGDATA_DIR/failover'" > $PGDATA_DIR/recovery.conf
fi

echo -n "Make backup curent config. files PostgreSQL-daemon from data directory $PGDATA_DIR ..."
mkdir -p $config_dir
cp -p $PGDATA_DIR/*.conf $config_dir/ && echo "saved to $config_dir."

echo "PostgreSQL-daemon stop .."
/usr/local/etc/rc.d/postgresql stop

echo "Cleaning all data in $PGDATA_DIR ..."
rm -rf $PGDATA_DIR/*

echo -n "Please, enter DATE archive backup-file like `date "+%Y%m%d_%H-%M"`:"
read DATE
echo -e "Fetch and Extract archive-file pgsql.$DATE.tar.bz2 in $PARENT_PGDATA ...\n"
cd $PARENT_PGDATA ; ftp ftp://backup-server/postgresql/pgsql.$DATE.tar.bz2
tar xpjf pgsql.$DATE.tar.bz2 -C $PGDATA_DIR && echo ".. done"

echo "Restore backup config-files and set hot_standby = on ...."
cd ${config_dir} && cp -p ./pg_hba.conf ./recovery.conf $PGDATA_DIR/
sed -I_master 's/^#hot_standby\ =\ off/hot_standby\ =\ on/g' $PGDATA_DIR/postgresql.conf

echo "Happy End: PostgreSQL-daemon start ....."
/usr/local/etc/rc.d/postgresql start
echo
echo "Done:"
/usr/local/etc/rc.d/postgresql status
echo
psql -Upgsql -d postgres -c "SELECT pg_is_in_recovery();"
ps auxww | grep 'postgres: wal receiver process' | grep -v grep 

После всех вышеописанны действий можем проверить успешно ли все прошло, проверив существование процессов ‘postgres: wal sender process’ и ‘postgres: wal receiver process’ на мастере и слейве, соответственно. Если что-то пошло не так, то полезным будет понаблюдать /var/log/messages, куда PosgreSQL пишет свои логи по умолчанию в FreeBSD, а также, возможно, заглянуть в файл postmaster.log в директории данных. Если все проделанно правильно, то остается настроить мониторинг и ждать очередных приятных нововведений в PostgreSQL 9.1 таких как:
— синхронная репликация;
— усовершенствования в асинхронной (streaming) репликации с точки зрения безопасности (для подключения к мастеру появиться специальный пользователь (роль), который не должен обладать привилегиями superuser);
— утилита pg_basebackup, которая для потоковой репликации сможет создавать бекап кластера БД, вместо того, чтобы в версии 9.0 посылать запрос в СУБД pg_start_backup(), последующего копирования кластера и запуска pg_stop_backup(), как сказанно в вики оффициального сайта:

> pg_basebackup -D /tmp/newcluster -U replication -v
NOTICE:pg_stop_backup complete,all required WAL segments have been archived
pg_basebackup: base backup completed 

pg_basebackup позволит создавать tar резервную копию кластера (с xlog-файлами или без), а также настроить слейв всего-лишь создав в новом инстансе файл recovery.conf;
— на слейве появится возможность останавливать репликацию с помощью pg_xlog_replay_pause() и pg_xlog_replay_resume(), что даст хороший инструмент для создания непротиворечивой резервной копии и отслеживания текущего состояния процесса репликации;
и другие полезные возможности и исправления!

Понравилась статья?
Подписаться на RSS feed
12 комментариев:
  1. MS Windows 27 июля, 2011

    Годная статья, много лучей благодарности

  2. Frosty 2 декабря, 2011

    Спасибо за статью. Пригодилась.

  3. Tat 31 января, 2012

    Спасибо за статью, полезно. Вышел новый PostgreSQL 9.1. Писали ли где-то, так же подробно, о репликации БД???

  4. Nemo 31 января, 2012

    Спасибо, приятно «слышать», что статья помогла сэкономить время в поиске нужной информации!
    Пока что, к сожалению, нет возможности написать о настройке репликации в текущей версии PostgreSQL, но обязательно это еще будет описано здесь.

  5. Tat 1 февраля, 2012

    Я изменила настройки
    master:
    pg_hba.conf
    host all all 192.168.1.123/32 trust
    postgresql.conf
    listen_address = ‘*’
    max_connections = 100
    shared_buffers = 2400MB
    wal_level = hot_standby
    checkpoint_segments = 16
    archive_mode = on
    archive_command = ‘cp %p /home/dbpsql/archive_xlogs/%f’
    max_wal_senders = 2
    wal_keep_segments = 32

    slave:
    pg_hba.conf
    host all all 192.168.1.124/32 trust
    postgresql.conf
    hot_standby = on
    recovery.conf
    standby_mode = ‘on’
    primary_conninfo = ‘host=postgres@192.168.1.124 port=5432 user=postgres’
    trigger_file = ‘/home/dbpsql/pgsql1/failover’
    restore_command = ‘cp /home/dbpsql/archive_xlogs/%f %p’
    archive_cleanup_command = ‘/usr/bin/pg_archivecleanup /home/dbpsql/archive_xlogs %r’

    и выполнила команды
    master:
    $ psql -c «SELECT pg_start_backup(‘label’, true)»
    $ rsync -a /home/dbpsql/archive_xlogs/ postgres@192.168.1.123:/home/dbpsql/archive_xlogs/
    $ psql -c «SELECT pg_stop_backup()»

    slave:
    $ psql -c «SELECT pg_is_in_recovery();»

    Файлы появляются на слейве, но базы не синхронизировались.
    И если на слейве присутствует файл recovery.conf, то база не стартует. Переименовываю этот файл — стартует.
    Все ли я сделала???? Что еще нужно, подскажите.

  6. Nemo 2 февраля, 2012

    Для репликации уже является возможным создать специального пользователя c атрибутом REPLICATION и в pg_hba.conf используем replication в качестве DATABASE.
    Настройки в pg_hba.conf на слейве на репликацию не влияют.
    Архивирование WAL-логов можно и отключить на время тестирования, дабы уменьшить вероятность запутаться.
    Если файла recovery.conf нет, то сервер не позиционирует себя как слейв, т.е. этот файл удалять\переименовывать на слейве не нужно.
    Здесь у вас проблема в том, что команда rsync копирует каталог archive_xlogs, но не выполняет синхронизацию файлов БД с мастера на слейв.
    Для создания бекапа кластера с мастера и переноса на слейв в 9.1 лучше пользоваться специально созданной для этого утилитой pg_basebackup.
    Если СУБД не стартует, то в первую очередь нужно смотреть какие ошибки пишутся в лог-файл.

  7. neoplanet 5 апреля, 2012

    Добрый день.

    Конфигурация: мастер-слейв (srv1-master, srv2-slave) репликация. pg 9.0.4. Репликация работает, нареканий нет кроме одного.

    Очистка wal архива для реплики на мастере, поскольку собирается и не подчищается автоматически.
    На слейве в recovery.conf прописал:
    archive_cleanup_command = ‘/../postgresql/9.0/bin/pg_archivecleanup -d srv1:/../postgresql/9.0/main/pg_wal_log %r 2>>/../postgresql/wal_arc.log’

    В wal_arc.log пишется следующее:
    pg_archivecleanup: keep WAL file «/../postgresql/9.0/main/pg_wal_log/file_name_xxx» and later

    При этом, как я понимаю, должно осуществляться удаление всех wal arc файлов на мастере кроме «file_name_xxx and later».
    Но этого не происходит.

    Помогите разобраться.

    Спасибо.

  8. Nemo 9 апреля, 2012

    С добрым!
    Попробуйте прописать в recovery.conf просто
    archive_cleanup_command = ‘/../postgresql/9.0/bin/pg_archivecleanup srv1:/../postgresql/9.0/main/pg_wal_log %r’, т.е. абсолютные пути к утилите pg_archivecleanup и директории с сохраненными логами с мастера (ARCHIVELOCATION), доступную для записи для слейва, и, конечно, переменную %r, указывающую на файл WAL, который нужно удалить (OLDESTKEPTWALFILE). В общем, на подобии, как в примере справки: archive_cleanup_command = ‘pg_archivecleanup /mnt/server/archiverdir %r’

  9. goglopseg 24 августа, 2012

    Спасибо. Прочитал с интересом. Блог в избранное занес=)

  10. slavka 25 ноября, 2013

    Большое спасибо за статью. Волей случая, после 7 лет ожидания и работы сисадмином, восстановился в институт. Практику как раз писал по реплицированию в PostgreSQL. С учетом того, что у меня очень плохо получается выражать свои мысли (тем более официальным языком и в письменном виде), во многом опирался на вашу статью. Очень меня выручили. Как порядочный человек — указал первоисточник.

    Еще раз большое вам спасибо!

  11. Nemo 27 ноября, 2013

    Спасибо! Рад, что усилия по написанию приносят пользу.

  12. Алексей 15 ноября, 2014

    Спасибо за Ваш труд! Не получалось правильно настроить репликацию, и только в Вашей статье нашёл буквально строчку, которая всё решила. Хотя в офдоке это было, но в разных местах, а здесь всё грамотно и удачно сведено в кучу. Ещё раз спасибо!

Оставить комментарий