Поточная репликация PostgreSQL
Теория подробно изложена в руководстве.
Ниже приведен пошаговый пример настройки репликации между двумя серверами
(db01 и db02) в терминах конфигурации Ansible.
Добавляем оба сервера в группу rsyncd:
[rsyncd:children]
dbXX
Включаем в rsyncd.conf модуль для доставки WAL-файлов:
[wal]
path = {{ postgresql.wal_dir }}
uid = {{ postgresql.user }}
gid = {{ postgresql.group }}
read only = no
Не забываем открыть файрволл для rsync:
# rsync
pass in proto tcp from <dbXX> to {{ net.primary.address }} port {{ rsyncd.port }}
Открываем файрволл для доступа к PostgreSQL:
# postgresql replication
{% for x in groups['dbXX'] %}
pass in proto tcp from {{ hostvars[ x ].net.primary.address }} to {{ net.primary.address }} port {{ postgresql.port }} # {{ hostvars[ x ].fqdn }}
{% endfor %}
Создаем каталоги на обеих серверах:
mkdir -m700 -p /data/wal && chown pgsql:pgsql /data/wal
В параметрах группы (group_vars/dbXX) указываем trigger_file:
postgresql:
trigger_file: trigger
В параметрах мастера (host_vars/db01) указываем куда отправлять WAL в файлах:
postgresql:
wal_send: ['db02.example.com']
В параметрах слейва (host_vars/db02) указываем откуда получать WAL по TCP:
postgresql:
wal_recv:
host: db01.example.com
port: 5432
user: replica
Создаем выделенного пользователя для репликации (только на мастере):
createuser -U pgsql -SDR --replication replica
И разрешаем ему ходить с хостов в группе репликации:
###################
# replication
###################
{% for x in groups['dbXX'] %}
host replication replica {{ hostvars[ x ].net.primary.address }}/32 trust
{% endfor %}
После этого выкатываем конфигурацию мастера:
ansible-playbook postgresql.yml -l db01 -D
Перезапускаем мастера, смотрим в логи и убеждаемся, что вызовами rsync он успешно отправляет WAL-файлы слейву:
service postgresql restart
fgrep 'WAL send' /var/log/pgsql/postgresql-2013-09-22.log
2013-09-22 22:20:08 MSK LOG: WAL sending 000000010000001E00000045 to db02.example.com
2013-09-22 22:20:57 MSK LOG: WAL sending 000000010000001E00000046 to db02.example.com
2013-09-22 22:21:03 MSK LOG: WAL sending 000000010000001E00000047 to db02.example.com
Останавливаем потенциального слейва, откладываем в сторону его каталог базы, создаем новый из копии мастера:
/usr/local/etc/rc.d/postgresql stop
mv /var/db/pgsql /var/db/pgsql.bak
pg_basebackup -Pv -D /var/db/pgsql -h db01.example.com -U replica
На этом шаге придется подождать (примерно половину от checkpoint_timeout), когда начнется и завершится принудительный checkpoint мастера, его можно увидеть в логах мастера:
fgrep -i checkpoint /var/log/pgsql/postgresql-2013-10-24.log
2013-10-24 14:24:18 MSK [2076]: [2175] db= LOG: checkpoint starting: force wait
2013-10-24 14:39:18 MSK [2076]: [2176] db= LOG: checkpoint complete: wrote 80720 buffers (1.0%); 0 transaction log file(s) added, 0 removed, 9 recycled; write=899.860 s, sync=0.025 s, total=899.909 s; sync files=187, longest=0.002 s, average=0.000 s
После того как данные приедут с мастера, исправим атрибуты каталога базы данных и (возможно) удалим старый каталог:
chmod 700 /var/db/pgsql && chown -R pgsql:pgsql /var/db/pgsql
rm -Rf /var/db/pgsql.bak
На предыдущем шаге вместе с базой приехали конфиги мастера, поэтому перевыкатываем конфиги на слейв и стартуем его:
ansible-playbook postgresql.yml -l db02 -D
Посмотреть на состояние репликации можно на мастере:
psql -U pgsql template1
select * from pg_stat_replication;
При необходимости аварийного превращения слейва в standalone мастер:
touch /var/db/pgsql/trigger