Replication slots в PostgreSQL

от автора

До девятой версии в PostgreSQL для создания «теплого» резервного сервера использовался WAL archiving. В версии 9.0 появилась потоковая репликация с возможностью создания «горячего» read-only сервера. В следующей версии PostgreSQL 9.4 появится новый функционал для создания потоковой репликации под названием replication slots. Рассмотрим что он собой представляет и чем отличается от предыдущих способов.
На сегодняшний момент доступен первый кандидат в релизы. В качестве тестового стенда выбраны 2 виртуалки под Ubuntu 14.04. Процесс сборки и установки одинаков для основного и резервного серверов. Ставим из исходников, предварительно поставив необходимые пакеты:

sudo apt-get update && sudo apt-get -y install make g++ checkinstall libreadline6-dev zlib1g-dev  

Скачиваем и распаковываем архив из репозитория:

wget https://ftp.postgresql.org/pub/source/v9.4rc1/postgresql-9.4rc1.tar.gz  tar xzf postgresql-9.4rc1.tar.gz  

Собираем и устанавливаем пакет:

cd postgresql-9.4rc1/  ./configure  make  sudo checkinstall  

По умолчанию бинарники для работы с СУБД ставятся в /usr/local/pgsql/.
Добавим пользователя postgres в систему:

sudo useradd -M postgres  

Создадим директорию для кластера:

sudo mkdir -p /data/db  sudo chown postgres:postgres /data/db  sudo chmod 0700 /data/db  

Далее выполняем действия на основном сервере. Инициализируем кластер:

sudo -u postgres /usr/local/pgsql/bin/initdb -D /data/db 

Кроме структуры кластера, initdb создаст дефолтные конфиги. Создадим в кластере директорию pg_log, в которой будут хранится логи:

sudo -u postgres mkdir /data/db/pg_log  sudo -u postgres chmod 0700 /data/db/pg_log  

Добавим записи в pg_hba.conf для подключения пользователей и чтобы резервный сервер мог забирать WAL-логи с основного:

host    all	                    all	                  192.168.1.0/24              md5  host    replication         replica           192.168.1.108/32          md5  

В конфиге postgresql.conf правим параметры:
listen_addresses = ‘*’ — слушать входящие соединения на всех интерфейсах
wal_level = hot_standby — необходимый формат WAL-логов для репликации
max_wal_senders = 2 — количество одновременных соединений для репликации
logging_collector = on — логи складываем в pg_log

Запускаем наш кластер:

sudo -u postgres /usr/local/pgsql/bin/pg_ctl -D /data/db start 

Смотрим состояние процессов:

ps aux | grep postgres  postgres 21295  0.0  0.0  23700   604 ?        Ss   13:39   0:00 postgres: logger process                  postgres 21297  0.0 13.6 170880 138408 ?  Ss   13:39   0:01 postgres: checkpointer process            postgres 21298  0.0  5.0 170784 51076 ?     Ss   13:39   0:00 postgres: writer process                  postgres 21299  0.0  0.5 170648  5148?       Ss   13:39   0:00 postgres: wal writer process              postgres 21300  0.0  0.1 171052  1836 ?      Ss   13:39   0:00 postgres: autovacuum launcher process     postgres 21301  0.2  0.1  25924  1060 ?        Ss   13:39   0:17 postgres: stats collector process 

Создадим пользователя replica с правами на репликацию:

/usr/local/pgsql/bin/psql -U postgres -c "create user replica with replication encrypted password '123'"  

Создадим тестовую базу с данными:

/usr/local/pgsql/bin/createdb -U postgres testdb  /usr/local/pgsql/bin/psql -U postgres -d testdb -c "create table testtable (id serial, data text)"  /usr/local/pgsql/bin/psql -U postgres -d testdb -c "insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,1000000)::text)" 

Настроим резервный сервер.
Создадим директорию для кластера:

sudo mkdir -p /data/db  sudo chmod 0700 /data/db  sudo chown postgres:postgres /data/db 

При помощи утилиты pg_basebackup сделаем резервную копию основного сервера:

sudo -u postgres /usr/local/pgsql/bin/pg_basebackup -h 192.168.1.103 -U replica -D /data/db -X s  

pg_basebackup копирует всё содержимое кластера, включая конфиги, поэтому изменяем параметр hot_standby в состояние on в postgresql.conf
Создадим файл recovery.conf в директории кластера, в котором укажем параметры подключения к основному серверу:

standby_mode='on'  primary_conninfo='host=192.168.1.103 port=5432 user=replica password=123'  

Запускаем кластер на резервном сервере:

sudo -u postgres /usr/local/pgsql/bin/pg_ctl -D /data/db start 

После этого на основном сервере должен запуститься процесс wal_sender, а на резервном wal_receiver:

Скрытый текст

postgres 21295  0.0  0.0  23700   604 ?        Ss   13:39   0:00 postgres: logger process                  postgres 21297  0.0  0.2 170756  2312 ?      Ss   13:39   0:00 postgres: checkpointer process            postgres 21298  0.0  0.2 170784  2252 ?      Ss   13:39   0:00 postgres: writer process                  postgres 21299  0.0  0.5 170648  5148 ?      Ss   13:39   0:00 postgres: wal writer process              postgres 21300  0.0  0.1 171052  1804 ?      Ss   13:39   0:00 postgres: autovacuum launcher process     postgres 21301  0.0  0.1  25924  1060 ?       Ss   13:39   0:00 postgres: stats collector process           postgres 21323  0.0  0.2 171048  2108 ?      Ss   13:46   0:00 postgres: wal sender process replica 192.168.1.108(56673) streaming 0/4E000210   postgres 15150  0.0  0.0  23700   612 ?       Ss   13:46   0:00 postgres: logger process                  postgres 15151  0.0  0.1 170788  1496 ?     Ss   13:46   0:00 postgres: startup process   recovering 00000001000000000000004E  postgres 15152  0.0  0.0 170680   944 ?       Ss   13:46   0:00 postgres: checkpointer process            postgres 15153  0.0  0.1 170680  1204 ?      Ss   13:46   0:00 postgres: writer process                  postgres 15154  0.0  0.0  25792   648 ?        Ss   13:46   0:00 postgres: stats collector process         postgres 15155  0.6  0.1 174956  1660 ?      Ss   13:46   0:00 postgres: wal receiver process   streaming 0/4E000138 

Посмотреть состояние репликации можно через представление pg_stat_replication на основном сервере

testdb=# select * from pg_stat_replication;  -[ RECORD 1 ]----+------------------------------  pid              | 21987  usesysid         | 16384  usename          | replica  application_name | walreceiver  client_addr      | 192.168.1.108  client_hostname  |  client_port      | 56674  backend_start    | 2014-11-25 18:30:09.206434+03  backend_xmin     |  state            | streaming  sent_location    | 0/5A2D8E60  write_location   | 0/5A2D8E60  flush_location   | 0/5A2D8E60  replay_location  | 0/5A2D8E60  sync_priority    | 0  sync_state       | async  

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

testdb=# insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,1000000)::text);  INSERT 0 1000000  testdb=# select * from pg_stat_replication;  -[ RECORD 1 ]----+------------------------------  pid              | 21987  usesysid         | 16384  usename          | replica  application_name | walreceiver  client_addr      | 192.168.1.108  client_hostname  |  client_port      | 56674  backend_start    | 2014-11-25 18:30:09.206434+03  backend_xmin     |  state            | streaming  sent_location    | 0/63800000  write_location   | 0/63680000  flush_location   | 0/63680000  replay_location  | 0/6136E160  sync_priority    | 0  sync_state       | async 

Здесь мы наблюдаем, что резервный сервер забрал с основного все WAL-логи, но еще не успел их все применить, поэтому он отстает от основного. По умолчанию, в postgres репликация происходит асинхронно при помощи WAL-логов, это бинарные файлы фиксированного размера в 16Мб, которые находятся в директории pg_xlog. Их количество можно менять при помощи параметров checkpoint_segments и wal_keep_segments. Когда количество измененных данных в кластере превышает общий размер WAL-логов, запускается процесс checkpointer, который сбрасывает WAL-логи в дата-файлы. После этого WAL-логи пересоздаются заново. В текущей стабильной версии postgres основной сервер не учитывает состояние резервного сервера. Поэтому если резервный слишком «отстал» от основного, то на основном WAL-логи пересоздадутся до того, как их заберет резервный. Попробуем смоделировать эту ситуацию.
Временно запретим резервному серверу подключаться на порт 5432:

sudo iptables -A OUTPUT -m tcp -p tcp —dport 5432 -j DROP 

Сгенерим еще данных на основном сервере:

testdb=# insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,1000000)::text);  INSERT 0 1000000 

Сбросим правило iptables и посмотрим логи резервного сервера, в которых наблюдаем такую неприятную картину.

LOG:  started streaming WAL from primary at 0/78000000 on timeline 1  FATAL:  could not receive data from WAL stream: ERROR:  requested WAL segment 000000010000000000000078 has already been removed 

Основной сервер удалил WAL-логи до того, как их успел забрать резервный. Теперь придется заново делать резервную копию основного сервера. Проблема в том, что основной сервер не учитывает состояние резервного. Поэтому если есть проблемы с сетью или просто медленный канал между серверами, то при интенсивной загрузке и/или изменении данных на основном сервере, возникает риск поломки репликации. Частичным решением является увеличение значения параметра wal_keep_segments, и включение WAL archiving. Но в версии 9.4 появятся replication slots. Рассмотрим как это работает:
На основном сервере создадим репликационный слот:

testdb=# SELECT pg_create_physical_replication_slot('standby_slot');  -[ RECORD 1 ]-----------------------+----------------  pg_create_physical_replication_slot | (standby_slot,)  

testdb=# select * from pg_replication_slots;  -[ RECORD 1 ]+-------------  slot_name    | standby_slot  plugin       |  slot_type    | physical  datoid       |  database     |  active       | f  xmin         |  catalog_xmin |  restart_lsn  |  

На резервном добавим к существующему содержимому файла recovery.conf строку
primary_slot_name = ‘standby_slot’

После перезапуска резервного сервера снова отключим его от основного и сгенерим на основном тестовые данных, которые превышают объем WAL-логов:

testdb=# insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,10000000)::text);  

Посмотрим параметры WAL-логов в системе, а потом реальное количество журнальных файлов в каталоге pg_xlog:

testdb=# show checkpoint_segments;  -[ RECORD 1 ]-------+--  checkpoint_segments | 3  

testdb=# show wal_keep_segments;  -[ RECORD 1 ]-----+--  wal_keep_segments | 0  

testdb=#\! ls /data/db/pg_xlog | wc -l  50 

Для расчета максимального количества WAL-файлов в системе используют формулу: (2 + checkpoint_completion_target) * checkpoint_segments + 1.
Однако текущее количество WAL-логов в системе значительно выше. Репликационные слоты сохраняют информацию о количестве скаченных WAL-логов каждым резервным сервером. Теперь WAL-логи будут копиться до тех пор, пока последний резервный сервер не заберет их или пока не будет удален репликационный слот. По мере скачивания WAL-логов, директория pg_xlog на основном сервере будет уменьшаться. Сбросив правило iptables на резервном сервере, в логах видим, что репликация возобновилась.

testdb=#\! tail -f /data/db/pg_log/postgresql-2014-11-27_191036.log  Is the server running on host "192.168.1.103" and accepting TCP/IP connections on port 5432? 	  LOG:  started streaming WAL from primary at 0/A0000000 on timeline 1 

Replication slots это отличный инструмент, повышающий надежность и удобство репликации в PostgreSQL.

Описание replication slots на официальном сайте PostgreSQL: www.postgresql.org/docs/9.4/static/warm-standby.html#STREAMING-REPLICATION-SLOTS

ссылка на оригинал статьи http://habrahabr.ru/post/245847/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *