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

Поскольку в нашей конфигурации не будет архива журнала предзаписи, важно на всех этапах использовать слот репликации - иначе при определенной задержке мастер может успеть удалить необходимые сегменты и весь процесс придется повторять с самого начала.

Создаем слот:

    α=> SELECT pg_create_physical_replication_slot('replica');

     pg_create_physical_replication_slot
    -------------------------------------
     (replica,)
    (1 row)

Вначале слот не инициализирован (restart_lsn пустой):

    α=> SELECT * FROM pg_replication_slots \gx

    -[ RECORD 1 ]-------+---------
    slot_name           | replica
    plugin              |
    slot_type           | physical
    datoid              |
    database            |
    temporary           | f
    active              | f
    active_pid          |
    xmin                |
    catalog_xmin        |
    restart_lsn         |
    confirmed_flush_lsn |

Как мы помним из модуля "Резервное копирование", в версии 10+ все необходимые настройки есть по умолчанию:

- wal_level = replica;
- max_wal_senders
- разрешение на подключение в pg_hba.conf.

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

    postgres$ rm -rf /var/lib/postgresql/10/beta/*

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

Возможность использовать слот появилась у pg_basebackup, начиная с версии 9.6. В более ранних версиях следовало бы заранее инициализировать слот, подключившись к нему утилитой pg_receive_xlog.

После выполнения резервной копии слот инициализировался, и мастер хранит все файлы журнала с начала копирования (restart_lsn).

    α=> SELECT * FROM pg_replication_slots \gx

    -[ RECORD 1 ]-------+----------
    slot_name           | replica
    plugin              |
    slot_type           | physical
    datoid              |
    database            |
    temporary           | f
    active              | f
    active_pid          |
    xmin                |
    catalog_xmin        |
    restart_lsn         | 0/8000000
    confirmed_flush_lsn |

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

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

Чтобы реплика выполняла запросы (была "горячей"), необходимо выставить параметр hot_standby. Если этого не сделать, реплика будет "теплой" и не будет принимать подключения.

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

Файл recovery.conf был подготовлен утилитой pg_basebackup, и уже включает указание режима непрерывного восстановления (standby_mode) и слота репликации (primary_slot_name):

    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'

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

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

    student$ sudo pg_ctlcluster 10 beta start

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

    postgres$ ps -o pid,command --ppid `head -n 1 /var/lib/postgresql/10/beta/postmaster.pid`

      PID COMMAND
     1427 postgres: 10/beta: startup process   waiting for 000000010000000000000009
     1428 postgres: 10/beta: checkpointer process
     1429 postgres: 10/beta: writer process
     1430 postgres: 10/beta: stats collector process
     1431 postgres: 10/beta: wal receiver process

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

Процессы wal writer и autovacuum launcher отсутствуют.

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

    postgres$ ps -o pid,command --ppid `head -n 1 /var/lib/postgresql/10/alpha/postmaster.pid`

      PID COMMAND
     1035 postgres: 10/alpha: checkpointer process
     1036 postgres: 10/alpha: writer process
     1037 postgres: 10/alpha: wal writer process
     1038 postgres: 10/alpha: autovacuum launcher process
     1039 postgres: 10/alpha: stats collector process
     1040 postgres: 10/alpha: bgworker: logical replication launcher
     1090 postgres: 10/alpha: student student [local] idle
     1432 postgres: 10/alpha: wal sender process student [local] idle

Здесь добавился процесс wal sender, обслуживающий подключение по протоколу репликации.

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

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

    α=> CREATE DATABASE replica_physical;

    CREATE DATABASE

    α=> \c replica_physical;

    You are now connected to database "replica_physical" as user "student".

    α=> CREATE TABLE test(s text);

    CREATE TABLE

    α=> INSERT INTO test VALUES ('Привет, мир!');

    INSERT 0 1

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

    student$ psql -p 5433 -d replica_physical

    β=> SELECT * FROM test;

          s
    --------------
     Привет, мир!
    (1 row)

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

    β=> INSERT INTO test VALUES ('Replica');

    ERROR:  cannot execute INSERT in a read-only transaction

Вообще реплику от мастера можно отличить с помощью функции:

    β=> SELECT pg_is_in_recovery();

     pg_is_in_recovery
    -------------------
     t
    (1 row)

# Мониторинг репликации

Состояние репликации можно смотреть в специальном представлении на мастере. Чтобы пользователь получил доступ к этой информации, ему должна быть выдана роль pg_read_all_stats (или он должен быть суперпользователем).

    α=> \c - postgres

    You are now connected to database "replica_physical" as user "postgres".

    α=> GRANT pg_read_all_stats TO student;

    GRANT ROLE

    α=> \c - student

    You are now connected to database "replica_physical" as user "student".

    α=> SELECT * FROM pg_stat_replication \gx

    -[ RECORD 1 ]----+------------------------------
    pid              | 1432
    usesysid         | 16384
    usename          | student
    application_name | walreceiver
    client_addr      |
    client_hostname  |
    client_port      | -1
    backend_start    | 2018-06-13 19:59:13.044052+03
    backend_xmin     |
    state            | streaming
    sent_lsn         | 0/9025620
    write_lsn        | 0/9025620
    flush_lsn        | 0/9025620
    replay_lsn       | 0/9025620
    write_lag        | 00:00:00.000199
    flush_lag        | 00:00:00.001131
    replay_lag       | 00:00:00.001184
    sync_priority    | 0
    sync_state       | async

Обратите внимание на поля *_lsn (и *_lag) - они показывают отставание реплики на разных этапах. Сейчас все позиции совпадают, отставание нулевое.

Теперь вставим в таблицу большое количество строк, чтобы увидеть репликацию в процессе работы.

    α=> INSERT INTO test SELECT 'Just a line' FROM generate_series(1,1000000);

    INSERT 0 1000000

    α=> SELECT *, pg_current_wal_lsn() from pg_stat_replication \gx

    -[ RECORD 1 ]------+------------------------------
    pid                | 1432
    usesysid           | 16384
    usename            | student
    application_name   | walreceiver
    client_addr        |
    client_hostname    |
    client_port        | -1
    backend_start      | 2018-06-13 19:59:13.044052+03
    backend_xmin       |
    state              | streaming
    sent_lsn           | 0/D1299E0
    write_lsn          | 0/D1299E0
    flush_lsn          | 0/D1299E0
    replay_lsn         | 0/C47A7FC
    write_lag          | 00:00:00.135193
    flush_lag          | 00:00:00.143305
    replay_lag         | 00:00:00.743007
    sync_priority      | 0
    sync_state         | async
    pg_current_wal_lsn | 0/D1299E0

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

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

    β=> SELECT count(*) FROM test;

      count
    ---------
     1000001
    (1 row)

Все строки успешно доехали.

И еще раз проверим состояние репликации:

    α=> SELECT *, pg_current_wal_lsn() from pg_stat_replication \gx

    -[ RECORD 1 ]------+------------------------------
    pid                | 1432
    usesysid           | 16384
    usename            | student
    application_name   | walreceiver
    client_addr        |
    client_hostname    |
    client_port        | -1
    backend_start      | 2018-06-13 19:59:13.044052+03
    backend_xmin       |
    state              | streaming
    sent_lsn           | 0/D1299E0
    write_lsn          | 0/D1299E0
    flush_lsn          | 0/D1299E0
    replay_lsn         | 0/D1299E0
    write_lag          | 00:00:00.135193
    flush_lag          | 00:00:00.143305
    replay_lag         | 00:00:00.54367
    sync_priority      | 0
    sync_state         | async
    pg_current_wal_lsn | 0/D1299E0

Все позиции выровнялись.

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