МАСТЕР: НАСТРОЙКА НЕПРЕРЫВНОГО АРХИВИРОВАНИЯ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Внесем необходимые изменения в конфигурацию. psql -h localhost -p 5432 -U postgres => alter system set wal_level = hot_standby; ALTER SYSTEM => alter system set archive_mode = on; ALTER SYSTEM => alter system set archive_command = 'test ! -f /home/postgres/archivedir/%f && cp %p /home/postgres/archivedir/%f && chmod g+r /home/postgres/archivedir/%f'; ALTER SYSTEM => alter system set max_standby_archive_delay = '10s'; ALTER SYSTEM => alter system set max_replication_slots = 5; ALTER SYSTEM => alter system set max_wal_senders = 5; ALTER SYSTEM ....................................................................... А также добавим пару параметров, которые надо будет изменить на реплике. => alter system set port = 5432; ALTER SYSTEM => alter system set hot_standby = off; ALTER SYSTEM ....................................................................... Очистим каталог /home/postgres/archivedir, куда будут сохраняться сегменты WAL. postgres> rm -rf /home/postgres/archivedir postgres> mkdir /home/postgres/archivedir postgres> ls -l /home/postgres/archivedir total 0 ....................................................................... МАСТЕР: ПРОВЕРКА ПОДКЛЮЧЕНИЯ ДЛЯ РЕПЛИКАЦИИ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ В файле pg_hba.conf должна быть строка для базы данных replication: postgres> sed -i s/#\(\w\+\s\+replication\)/\1/ /usr/local/pgsql/data/pg_hba.conf postgres> tail -n 5 /usr/local/pgsql/data/pg_hba.conf # Allow replication connections from localhost, by a user with the # replication privilege. local replication postgres trust host replication postgres 127.0.0.1/32 trust host replication postgres ::1/128 trust Все в порядке. ....................................................................... Перезапустим сервер, чтобы изменения вступили в силу. => \q postgres> pg_ctl restart -w -m fast -l /home/postgres/logfile waiting for server to shut down.... done server stopped waiting for server to start.... done server started ....................................................................... МАСТЕР: СОЗДАНИЕ БАЗОВОЙ РЕЗЕРВНОЙ КОПИИ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Создадим базовую резервную копию. Убедимся, что в кластере нет пользовательских табличных пространств, так как их наличие усложнило бы процесс резервирования и восстановления. psql -h localhost -p 5432 -U postgres => \db List of tablespaces Name | Owner | Location ------------+----------+---------- pg_default | postgres | pg_global | postgres | (2 rows) ....................................................................... Создадим тестовую таблицу, которую будем использовать для проверки репликации. => create database db10; CREATE DATABASE => \c db10 You are now connected to database "db10" as user "postgres". => create table replica_test(t text); CREATE TABLE ....................................................................... Выполним команду pg_basebackup. Используем формат по умолчанию (plain), в качестве каталога для сохранения сразу укажем PGDATA будущей реплики. postgres2> bash -c "rm -rf /usr/local/pgsql2/data/*" postgres2> pg_basebackup -U postgres -p 5432 -D /usr/local/pgsql2/data NOTICE: pg_stop_backup complete, all required WAL segments have been archived ....................................................................... Проверим содержимое каталога: postgres2> ls -l /usr/local/pgsql2/data total 128 -rw------- 1 postgres2 postgres2 208 дек. 14 18:59 backup_label -rw------- 1 postgres2 postgres2 208 дек. 14 18:59 backup_label.old drwx------ 30 postgres2 postgres2 4096 дек. 14 18:59 base drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 global drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_clog drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_commit_ts drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_dynshmem -rw------- 1 postgres2 postgres2 4465 дек. 14 18:59 pg_hba.conf -rw------- 1 postgres2 postgres2 1636 дек. 14 18:59 pg_ident.conf drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_log drwx------ 4 postgres2 postgres2 4096 дек. 14 18:59 pg_logical drwx------ 4 postgres2 postgres2 4096 дек. 14 18:59 pg_multixact drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_notify drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_replslot drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_serial drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_snapshots drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_stat drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_stat_tmp drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_subtrans drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_tblspc drwx------ 2 postgres2 postgres2 4096 дек. 14 18:59 pg_twophase -rw------- 1 postgres2 postgres2 4 дек. 14 18:59 PG_VERSION drwx------ 3 postgres2 postgres2 4096 дек. 14 18:59 pg_xlog -rw------- 1 postgres2 postgres2 387 дек. 14 18:59 postgresql.auto.conf -rw------- 1 postgres2 postgres2 21672 дек. 14 18:59 postgresql.conf -rw-r--r-- 1 postgres2 postgres2 127 дек. 14 18:59 recovery.done ....................................................................... Также проверим, что настроенное архивирование работает правильно: postgres> ls -l /home/postgres/archivedir total 32772 -rw-r----- 1 postgres postgres 16777216 дек. 14 18:59 0000001100000003000000B3 -rw-r----- 1 postgres postgres 16777216 дек. 14 18:59 0000001100000003000000B4 -rw-r----- 1 postgres postgres 305 дек. 14 18:59 0000001100000003000000B4.00000024.backup Сегменты архивируются, права на доступ выставлены в соответствии с archive_command: u=rw,g=r. ....................................................................... РЕПЛИКА: НАСТРОЙКИ ~~~~~~~~~~~~~~~~~~ Требуется немного изменить postgresql.auto.conf. Конечно, его надо изменять командой alter system, но наш экземпляр еще не запущен. postgres2> sed -i "s/port = .*/port = 5433/" /usr/local/pgsql2/data/postgresql.auto.conf postgres2> sed -i "s/hot_standby = .*/hot_standby = on/" /usr/local/pgsql2/data/postgresql.auto.conf postgres2> cat /usr/local/pgsql2/data/postgresql.auto.conf # Do not edit this file manually! # It will be overwritten by ALTER SYSTEM command. wal_level = 'hot_standby' archive_mode = 'on' archive_command = 'test ! -f /home/postgres/archivedir/%f && cp %p /home/postgres/archivedir/%f && chmod g+r /home/postgres/archivedir/%f' max_standby_archive_delay = '10s' max_replication_slots = '5' max_wal_senders = '5' port = 5433 hot_standby = on ....................................................................... Теперь создадим файл recovery.conf. postgres2> bash -c "echo standby_mode = on >> /usr/local/pgsql2/data/recovery.conf" postgres2> bash -c "echo restore_command = \\'\'cp /home/postgres/archivedir/%f %p\\'\' >> /usr/local/pgsql2/data/recovery.conf" postgres2> cat /usr/local/pgsql2/data/recovery.conf standby_mode = on restore_command = 'cp /home/postgres/archivedir/%f %p' ....................................................................... РЕПЛИКА: СТАРТ СЕРВЕРА ~~~~~~~~~~~~~~~~~~~~~~ Можно стартовать сервер. postgres2> pg_ctl start -w -l /home/postgres2/logfile waiting for server to start..... done server started ....................................................................... Посмотрим на процессы реплики. postgres2> ps -o pid,command --ppid `sudo head -n 1 /usr/local/pgsql2/data/postmaster.pid` PID COMMAND 14113 postgres: startup process waiting for 0000001100000003000000B5 14119 postgres: checkpointer process 14120 postgres: writer process 14121 postgres: stats collector process ....................................................................... И сравним с процессами мастера. postgres> ps -o pid,command --ppid `sudo head -n 1 /usr/local/pgsql/data/postmaster.pid` PID COMMAND 14040 postgres: checkpointer process 14041 postgres: writer process 14042 postgres: wal writer process 14043 postgres: autovacuum launcher process 14044 postgres: archiver process last was 0000001100000003000000B4.00000024.backup 14045 postgres: stats collector process 14068 postgres: postgres db10 127.0.0.1(50277) idle ....................................................................... ПРОВЕРКА РЕПЛИКАЦИИ ~~~~~~~~~~~~~~~~~~~ Подключимся к серверам и проверим таблицу: => select * from replica_test; t --- (0 rows) | psql -h localhost -p 5433 -U postgres | => \c db10 | You are now connected to database "db10" as user "postgres". | => select * from replica_test; | t | --- | (0 rows) | Таблица ожидаемо восстановилась из резервной копии. ....................................................................... Теперь вставим в таблицу строку на мастере. => insert into replica_test values ('one'); INSERT 0 1 Будет ли видна эта строка на реплике? ....................................................................... Не будет, поскольку сегмент WAL не заполнился и не попал в архив. | => select * from replica_test; | t | --- | (0 rows) | ....................................................................... Вызовем переключение сегмента вручную. => select pg_switch_xlog(); pg_switch_xlog ---------------- 3/B500009C (1 row) Через некоторое время строка появится и на реплике. ....................................................................... | => select * from replica_test; | t | ----- | one | (1 row) | ....................................................................... Теперь смоделируем конфликт. Чтобы не создавать на реплике долгоиграющий запрос, просто начнем транзакцию с уровнем изоляции repeatable read. В начале транзакции на реплике будет сделан снимок, а необходимые для него версии строк мы очистим. => update replica_test set t = 'two'; UPDATE 1 ....................................................................... | => begin; | BEGIN | => set transaction isolation level repeatable read; | SET | => select * from replica_test; | t | ----- | one | (1 row) | Снимок на реплике "видит" первую версию строки. ....................................................................... => vacuum replica_test; VACUUM Когда конфликтующая запись передастся на реплику, ее применение будет отложено на max_standby_archive_delay (у нас 10 секунд). Поэтому после переключения сегмента выполним на реплике несколько запросов к таблице с интервалом в 5 секунд. ....................................................................... => select pg_switch_xlog(); pg_switch_xlog ---------------- 3/B6002958 (1 row) sleep 5 | => select * from replica_test; | t | ----- | one | (1 row) | sleep 5 | => select * from replica_test; | t | ----- | one | (1 row) | sleep 5 | => select * from replica_test; | FATAL: terminating connection due to conflict with recovery | DETAIL: User query might have needed to see row versions that must be removed. | HINT: In a moment you should be able to reconnect to the database and repeat your command. | server closed the connection unexpectedly | This probably means the server terminated abnormally | before or while processing the request. | connection to server was lost | | sleep 5 | => select * from replica_test; | | ....................................................................... Как мы видим, конфликтующий запрос был остановлен. Приложение могло бы попробовать повторить его в надежде, что конфликт не возникнет повторно. Конец демонстрации. ....................................................................... => alter system reset all; ALTER SYSTEM => \q | => \q