Настройка для pg_rewind

Мы планируем использовать утилиту pg_rewind, поэтому убедимся, что включены контрольные суммы на страницах данных:

student$ psql 
α=> SHOW data_checksums;
 data_checksums 
----------------
 on
(1 row)

Этот параметр служит только для информации; изменить его нельзя - подсчет контрольных сумм включается при инициализации кластера (включение "на лету" планируется, но появится не раньше версии 12).

И проверим, что параметр full_page_writes включен:

α=> SHOW full_page_writes;
 full_page_writes 
------------------
 on
(1 row)


Настройка репликации без архива

Процесс настройки реплики аналогичен рассмотренному в предыдущей теме.

Слот:

α=> SELECT pg_create_physical_replication_slot('replica');
 pg_create_physical_replication_slot 
-------------------------------------
 (replica,)
(1 row)


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

postgres$ rm -rf /var/lib/postgresql/10/beta/*
postgres$ pg_basebackup -U student --pgdata=/var/lib/postgresql/10/beta -R --slot=replica

Меняем порт и включаем режим горячего резерва:

postgres$ echo 'port = 5433' >> /var/lib/postgresql/10/beta/postgresql.auto.conf
postgres$ echo 'hot_standby = on' >> /var/lib/postgresql/10/beta/postgresql.auto.conf

Файл recovery.conf подготовлен утилитой pg_basebackup:

postgres$ cat /var/lib/postgresql/10/beta/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=student passfile=''/var/lib/postgresql/.pgpass'' host=''/var/run/postgresql'' port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres target_session_attrs=any'
primary_slot_name = 'replica'

Запускаем реплику.

student$ sudo pg_ctlcluster 10 beta start

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

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

α=> CREATE DATABASE replica_switchover;
CREATE DATABASE
α=> \c replica_switchover;
You are now connected to database "replica_switchover" as user "student".
α=> CREATE TABLE test(s text);
CREATE TABLE
α=> INSERT INTO test VALUES ('Привет, мир!');
INSERT 0 1

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

student$ psql -p 5433 -d replica_switchover
β=> SELECT * FROM test;
      s       
--------------
 Привет, мир!
(1 row)


Переход на реплику

Сейчас второй сервер является репликой (находится в режиме восстановления):

β=> SELECT pg_is_in_recovery();
 pg_is_in_recovery 
-------------------
 t
(1 row)


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

student$ sudo pg_ctlcluster 10 beta promote

Теперь бывшая реплика стала полноценным экземпляром.

β=> SELECT pg_is_in_recovery();
 pg_is_in_recovery 
-------------------
 f
(1 row)

Мы можем изменять данные:

β=> INSERT INTO test VALUES ('Я - бывшая реплика (новый мастер).');
INSERT 0 1

Между тем первый сервер еще не выключен и тоже может изменять данные:

α=> INSERT INTO test VALUES ('Die hard');
INSERT 0 1

В реальности такой ситуации необходимо всячески избегать, поскольку теперь непонятно, какому серверу верить. Придется либо полностью потерять изменения на одном из серверов, либо придумывать, как объединить данные.

Наш выбор - потерять изменения, сделанные на первом сервере. Остановим его (аккуратно, с выполнением контрольной точки).

α=> \q
student$ sudo pg_ctlcluster 10 alpha stop

Возвращение в строй бывшего мастера

Создадим на втором сервере слот для будущей реплики.

β=> SELECT pg_create_physical_replication_slot('replica');
 pg_create_physical_replication_slot 
-------------------------------------
 (replica,)
(1 row)

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


В ключах утилиты надо указать каталог PGDATA целевого сервера и способ обращения к серверу-источнику: либо подключение от имени суперпользователя (если сервер работает), либо местоположение его каталога PGDATA (если он выключен).

postgres$ /usr/lib/postgresql/10/bin/pg_rewind -D /var/lib/postgresql/10/alpha --source-server='user=postgres port=5433' -P
connected to server
servers diverged at WAL location 0/F025744 on timeline 1
rewinding from last common checkpoint at 0/F001580 on timeline 1
reading source file list
reading target file list
reading WAL in target
need to copy 54 MB (total source directory size is 83 MB)
    0/55990 kB (0%) copied
55990/55990 kB (100%) copied
creating backup label and updating control file
syncing target data directory
Done!

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

Заглянем в backup_label:

postgres$ cat /var/lib/postgresql/10/alpha/backup_label
START WAL LOCATION: 0/F001548 (file 00000001000000000000000F)
CHECKPOINT LOCATION: 0/F001580
BACKUP METHOD: pg_rewind
BACKUP FROM: standby
START TIME: 2018-06-13 19:59:36 MSK

Файл postgresql.auto.conf был скопирован с нового мастера, его нужно исправить.

postgres$ echo 'hot_standby = on' > /var/lib/postgresql/10/alpha/postgresql.auto.conf

Чтобы бывший мастер после восстановления стал новой репликой, потребуется файл recovery.conf.

postgres$ echo $'standby_mode = \'on\'' > /var/lib/postgresql/10/alpha/recovery.conf
postgres$ echo $'primary_conninfo = \'user=postgres port=5433\'' >> /var/lib/postgresql/10/alpha/recovery.conf
postgres$ echo $'primary_slot_name = \'replica\'' >> /var/lib/postgresql/10/alpha/recovery.conf

Вот что вышло:

postgres$ cat /var/lib/postgresql/10/alpha/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=postgres port=5433'
primary_slot_name = 'replica'

Можно стартовать новую реплику.

student$ sudo pg_ctlcluster 10 alpha start

Слот репликации инициализировался и используется:

β=> SELECT * FROM pg_replication_slots \gx
-[ RECORD 1 ]-------+----------
slot_name           | replica
plugin              | 
slot_type           | physical
datoid              | 
database            | 
temporary           | f
active              | t
active_pid          | 3143
xmin                | 
catalog_xmin        | 
restart_lsn         | 0/F04A1CC
confirmed_flush_lsn | 


Данные, измененные на новом мастере, получены:

student$ psql -p 5432 -d replica_switchover
α=> SELECT * FROM test;
                 s                  
------------------------------------
 Привет, мир!
 Я - бывшая реплика (новый мастер).
(2 rows)


Проверим еще:

β=> INSERT INTO test VALUES ('Еще строка с нового мастера.');
INSERT 0 1
α=> SELECT * FROM test;
                 s                  
------------------------------------
 Привет, мир!
 Я - бывшая реплика (новый мастер).
 Еще строка с нового мастера.
(3 rows)

Таким образом, два сервера поменялись ролями.


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