Мы планируем использовать утилиту 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)
Таким образом, два сервера поменялись ролями.
Конец демонстрации.