# Настройка для 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)

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

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