Физическая репликация. Резервная копия мастера

Начиная с версии 10, все необходимые настройки уже присутствуют по умолчанию:

Создадим автономную резервную копию. В качестве каталога для сохранения сразу используем PGDATA резервного сервера. Ключ -R создаст заготовку управляющего файла recovery.conf.

postgres$ rm -rf /usr/local/pgsql2/data/*
postgres$ pg_basebackup --pgdata=/usr/local/pgsql2/data -R

Резервный сервер уже предварительно собран и установлен.


Реплика

Мы собираемся запустить второй сервер одновременно с основным на одной машине, поэтому в настройках необходимо поменять порт:

postgres$ echo 'port = 5433' >> /usr/local/pgsql2/data/postgresql.auto.conf

И добавим параметр горячего резерва, чтобы реплика принимала запросы на чтение:

postgres$ echo 'hot_standby = on' >> /usr/local/pgsql2/data/postgresql.auto.conf

Заготовка для recovery.conf была подготовлена утилитой pg_basebackup, и она нас устраивает:

postgres$ cat /usr/local/pgsql2/data/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=postgres passfile=''/home/postgres/.pgpass'' port=5432 sslmode=disable sslcompression=1 target_session_attrs=any'

Можно запускать сервер.

postgres$ pg_ctl -w -l /home/postgres/logfile2 -D /usr/local/pgsql2/data start
waiting for server to start.... done
server started

В приведенной команде мы явно указываем расположение каталога с данными кластера. Для удобства в виртуальной машине есть команды "1" и "2", которые переключают окружение на первый и на второй сервер соответственно.


Посмотрим на процессы реплики.

postgres$ ps -o pid,command --ppid `head -n 1 /usr/local/pgsql2/data/postmaster.pid`
  PID COMMAND
 1283 postgres: startup process   waiting for 000000010000000000000008
 1284 postgres: checkpointer process   
 1285 postgres: writer process   
 1286 postgres: stats collector process   
 1287 postgres: wal receiver process   

Процесс wal receiver принимает поток журнальных записей, процесс startup применяет изменения.


И сравним с процессами мастера.

postgres$ ps -o pid,command --ppid `head -n 1 /usr/local/pgsql/data/postmaster.pid`
  PID COMMAND
 1153 postgres: postgres postgres [local] idle
 1288 postgres: wal sender process postgres [local] idle
19616 postgres: checkpointer process   
19617 postgres: writer process   
19618 postgres: wal writer process   
19619 postgres: autovacuum launcher process   
19620 postgres: stats collector process   
19621 postgres: bgworker: logical replication launcher   

Здесь добавился процесс wal sender.


Проверка репликации

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

postgres$ psql -p 5432
=> SELECT * FROM pg_stat_replication \gx
-[ RECORD 1 ]----+------------------------------
pid              | 1288
usesysid         | 10
usename          | postgres
application_name | walreceiver
client_addr      | 
client_hostname  | 
client_port      | -1
backend_start    | 2018-12-24 17:30:24.266277+03
backend_xmin     | 
state            | streaming
sent_lsn         | 0/8000000
write_lsn        | 0/8000000
flush_lsn        | 0/8000000
replay_lsn       | 0/8000000
write_lag        | 00:00:00.100718
flush_lag        | 00:00:00.100718
replay_lag       | 00:00:00.100718
sync_priority    | 0
sync_state       | async


Выполним несколько команд на мастере:

=> CREATE DATABASE replica_overview;
CREATE DATABASE
=> \c replica_overview;
You are now connected to database "replica_overview" as user "postgres".
=> CREATE TABLE test(id integer PRIMARY KEY, descr text);
CREATE TABLE

Проверим реплику:

postgres$ psql -p 5433 -d replica_overview
=> SELECT * FROM test;
 id | descr 
----+-------
(0 rows)


=> INSERT INTO test VALUES (1, 'Раз');
INSERT 0 1

=> SELECT * FROM test;
 id | descr 
----+-------
  1 | Раз
(1 row)

При этом изменения на реплике не допускаются:

=> INSERT INTO test VALUES (2, 'Два');
ERROR:  cannot execute INSERT in a read-only transaction

Логическая репликация

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

postgres$ pg_ctl -w -l /home/postgres/logfile2 -D /usr/local/pgsql2/data promote
waiting for server to promote.... done
server promoted
=> INSERT INTO test VALUES (2, 'Два');
INSERT 0 1

Далее мы хотим настроить между серверами логическую репликацию. Для этого нам понадобится дополнительная информация в журнале.

=> ALTER SYSTEM SET wal_level = logical;
ALTER SYSTEM
postgres$ pg_ctl -w -l /home/postgres/logfile -D /usr/local/pgsql/data restart
waiting for server to shut down.... done
server stopped
waiting for server to start.... done
server started

На первом сервере создаем публикацию:

postgres$ psql -d replica_overview
=> CREATE PUBLICATION test_pub FOR TABLE test;
CREATE PUBLICATION
=> \dRp+
                Publication test_pub
  Owner   | All tables | Inserts | Updates | Deletes 
----------+------------+---------+---------+---------
 postgres | f          | t       | t       | t
Tables:
    "public.test"


На втором сервере подписываемся на эту публикацию (отключаем первоначальное копирование данных):

=> CREATE SUBSCRIPTION test_sub
CONNECTION 'host=localhost port=5432 user=postgres dbname=replica_overview'
PUBLICATION test_pub WITH (copy_data = false);

NOTICE:  created replication slot "test_sub" on publisher
CREATE SUBSCRIPTION
=> \dRs
            List of subscriptions
   Name   |  Owner   | Enabled | Publication 
----------+----------+---------+-------------
 test_sub | postgres | t       | {test_pub}
(1 row)


=> INSERT INTO test VALUES (3, 'Три');
INSERT 0 1

=> SELECT * FROM test;
 id | descr 
----+-------
  1 | Раз
  2 | Два
  3 | Три
(3 rows)


Состояние подписки можно посмотреть в представлении:

=> SELECT * FROM pg_stat_subscription \gx
-[ RECORD 1 ]---------+------------------------------
subid                 | 24576
subname               | test_sub
pid                   | 1880
relid                 | 
received_lsn          | 0/802E0DC
last_msg_send_time    | 2018-12-24 17:30:27.945703+03
last_msg_receipt_time | 2018-12-24 17:30:27.946034+03
latest_end_lsn        | 0/802E0DC
latest_end_time       | 2018-12-24 17:30:27.945703+03


К процессам сервера добавился logical replication worker (его номер указан в pg_stat_subscription.pid):

postgres$ ps -o pid,command --ppid `head -n 1 /usr/local/pgsql2/data/postmaster.pid`
  PID COMMAND
 1284 postgres: checkpointer process   
 1285 postgres: writer process   
 1286 postgres: stats collector process   
 1607 postgres: postgres replica_overview [local] idle
 1725 postgres: wal writer process   
 1729 postgres: autovacuum launcher process   
 1732 postgres: bgworker: logical replication launcher   
 1880 postgres: bgworker: logical replication worker for subscription 24576  

Если репликация больше не нужна, надо аккуратно удалить подписку - иначе на публикующем сервере останется открытым репликационный слот.

=> DROP SUBSCRIPTION test_sub;
NOTICE:  dropped replication slot "test_sub" on publisher
DROP SUBSCRIPTION

Конец демонстрации.