Перейти к основному содержимому

Физическая репликация

  1. Удалите БД monman_db и ts_db, табличное пространство ts_lab и его каталог.

    postgres@postgres=# DROP DATABASE monman_db;
    DROP DATABASE
    postgres@postgres=# DROP DATABASE ts_db;
    DROP DATABASE
    postgres@postgres=# DROP TABLESPACE ts_lab;
    DROP TABLESPACE

    Выйдите из psql и удалите оставшиеся файлы.

    postgres@postgres=# \q
    [postgres@ServerName ~]$ rm -rf *.log ts_data/
  2. Создайте слот физической репликации.

    Подключитесь к серверу и выполните запрос.

    [postgres@ServerName ~]$ psql
    postgres@postgres=# SELECT pg_create_physical_replication_slot('rslot');
    pg_create_physical_replication_slot
    -------------------------------------
    (rslot, )
    (1 row)

    Проверьте, что слот создан.

    postgres@postgres=# SELECT * FROM pg_replication_slots \gx
    -[ RECORD 1 ]-----------+--------
    slot_name | rslot
    plugin |
    slot_type | physical
    dataoid |
    database |
    temporary | f
    active | f
    active_pid |
    xmin |
    catalog_xmin |
    restart_lsn |
    comfirmed_flush_lsn |
    wal_status |
    safe_wal_size |
    two_phase | f

    Слот rslot создан как физический (slot_type = physical), но еще не активен (active = f).

  3. Проверьте настройку wal_level и достаточность процессов и слотов репликации.

    Выполните запрос к конфигурации.

    postgres@postgres=# \dconfig (max_(*send|repl)*|wal_level)
    Разбор команды

    • \dconfig — метакоманда для отображения параметров конфигурации PostgreSQL;
    • (max_(*send|repl)*|wal_level) — регулярное выражение, фильтрующее параметры: max_wal_senders, max_replication_slots и wal_level.
    List of configuration parameters
    Parameter | Value
    -----------------------+---------
    max_replication_slots | 10
    max_wal_senders | 10
    wal_level | replica
    (3 rows)

    Параметр wal_level установлен в replica, что достаточно для физической репликации. Количество слотов и процессов wal_sender — по 10 каждого.

  4. Создайте физическую копию, используя слот репликации, а также автоматически создав настройку для сервера-реплики.

    Выполните pg_basebackup.

    [postgres@ServerName ~]$ pg_basebackup -c fast -S rslot -R -D repl
    Разбор команды

    • -c fast — выполняет быструю контрольную точку перед началом копирования;
    • -S rslot — использует слот репликации rslot для резервного копирования;
    • -R — автоматически создает файл standby.signal и запись primary_conninfo в postgresql.auto.conf;
    • -D repl — целевой каталог для резервной копии.

    Проверьте, что каталог создан.

    [postgres@ServerName ~]$ ls -l
    total 8
    drwx------ 25 postgres postgres 4096 Nov 11 13:58 repl
  5. Перейдите в каталог repl. Проверьте настройки в postgresql.auto.conf и наличие файла standby.signal.

    Перейдите в каталог.

    [postgres@ServerName ~]$ cd repl/

    Выведите содержимое каталога.

    [postgres@ServerName repl]$ ls
    backup_label log pg_hba.conf.orig pg_multixact pg_prep_stats pg_snapshots
    pg_tblspc pg_xact PRODUCT_VERSION
    backup_manifest pg_commit_ts pg_ident.conf pg_notify pg_quota.conf pg_stat
    pg_twophase postgresql.auto.conf standby.signal
    base pg_dynshem pg_integrity pg_perf_insights pg_replslot pg_stat_tmp
    PG_VERSION postgresql.conf tracing
    global pg_hba.conf pg_logical pg_pp_cache pg_serial pg_subtrans pg_wal
    postgresql.conf.orig

    Файл standby.signal присутствует — сервер запустится в режиме реплики.

    Проверьте настройки в postgresql.auto.conf.

    [postgres@ServerName repl]$ cat postgresql.auto.conf
    # Do not edit this file manually!
    # It will be overwritten by the ALTER SYSTEM command.
    primary_conninfo = 'user=postgres passfile=''/var/lib/postgres/.pgpass'' channel_binding=prefer
    port=5432 client_encoding=UTF8 sslmode=prefer sslcompression=0 sslsni=1
    ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'
    primary_slot_name = 'rslot'

    В настройках указано имя слота primary_slot_name = 'rslot' и параметры подключения к мастер-серверу.

  6. Настройте реплику на использование порта 7432.

    Найдите строку с параметром port.

    [postgres@ServerName repl]$ grep -n ^#*port postgresql.conf
    64:#port = 5432 # (change requires restart)

    Замените порт на 7432.

    [postgres@ServerName repl]$ sed -i.bak '64s/^.*$/port = 7432/' postgresql.conf
    Разбор команды

    • sed -i.bak — редактирование с сохранением бэкапа (расширение .bak);
    • '64s/^.*$/port = 7432/' — в 64-й строке заменить все содержимое на port = 7432;
    • postgresql.conf — целевой файл конфигурации.

    Проверьте результат.

    [postgres@ServerName repl]$ diff postgresql.conf.bak postgresql.conf
    64c64
    < #port = 5432 # (change requires restart)
    ---
    > port = 7432
  7. Запустите реплику.

    Выполните pg_ctl start.

    [postgres@ServerName ~]$ pg_ctl start -D ~/repl/ -l repl_srv.log
    waiting for server to start...... done
    server started
  8. Проверьте журнал отчета реплики.

    Выведите содержимое лога.

    [postgres@ServerName ~]$ cat repl_srv.log
    2024-11-11 14:17:13.816 MSK [66908] LOG: License type is "Trial"
    2024-11-11 14:17:13.816 MSK [66908] LOG: Licensee is "Educational license for VM with Pangolin"
    2024-11-11 14:17:13.816 MSK [66908] LOG: License expire date is "2025-01-31 23:59:59.816912+03"
    2024-11-11 14:17:13.816 MSK [66908] LOG: License CPUs number allowed: 2
    2024-11-11 14:17:13.816 MSK [66908] LOG: License allowed memory in bytes: unrestricted
    2024-11-11 14:17:13.817 MSK [66908] WARNING: postgres: Could not init KMS connection. Error: -52
    (failed to lock file)
    2024-11-11 14:17:13.817 MSK [66908] LOG: configuration file "/var/lib/postgres/repl/pg_quota.conf"
    contains no entries
    2024-11-11 14:17:13.938 MSK [66908] LOG: product version: Platform V Pangolin {pangolin_version}
    2024-11-11 14:17:13.938 MSK [66908] LOG: product build info: build 69 (13:53:00 27.04.2024) commit
    f8acb7233c42e22cd2b0767c435018b32a43476f
    2024-11-11 14:17:13.938 MSK [66908] LOG: starting PostgreSQL 15.5 on x86_64-pc-linux-gnu, compiled
    by gcc (GCC) 8.3.1 20191121 (Red Hat 8.3.1-6), 64-bit
    2024-11-11 14:17:13.938 MSK [66908] LOG: listening on IPv4 address "0.0.0.0", port 7432
    2024-11-11 14:17:13.938 MSK [66908] LOG: listening on IPv6 address "::", port 7432
    2024-11-11 14:17:13.946 MSK [66908] LOG: listening on Unix socket "/tmp/.s.PGSQL.7432"
    2024-11-11 14:17:13.966 MSK [66908] LOG: database system was interrupted; last known up at 2024-11-
    11 13:58:47 MSK
    2024-11-11 14:17:13.970 MSK [66908] LOG: idle terminator started
    2024-11-11 14:17:16.022 MSK [66908] LOG: entering standby mode
    2024-11-11 14:17:16.052 MSK [66908] LOG: redo starts at 0/AC000028
    2024-11-11 14:17:16.077 MSK [66908] LOG: consistent recovery state reached at 0/AC000130
    2024-11-11 14:17:16.077 MSK [66908] LOG: database system is ready to accept read-only connections
    2024-11-11 14:17:16.086 MSK [66908] LOG: Start integrity check launcher
    2024-11-11 14:17:16.088 MSK [66908] LOG: Start of integrity check
    2024-11-11 14:17:16.094 MSK [66908] LOG: License checker started
    2024-11-11 14:17:16.103 MSK [66908] LOG: started streaming WAL from primary at 0/AD000000 on
    timeline 1

    Реплика перешла в standby mode, достигла консистентного состояния и начала стриминг WAL от мастера.

  9. Проверьте, что к реплике можно обращаться с читающими запросами.

    Выполните запрос к функции pg_is_in_recovery().

    [postgres@ServerName ~]$ psql -p 7432 -c 'SELECT pg_is_in_recovery()'
    pg_is_in_recovery
    -------------------
    t
    (1 row)

    Сервер на порту 7432 находится в режиме восстановления (t), что подтверждает его статус реплики.

  10. Выполните на реплике запрос, выдающий список БД.

Выполните psql с опцией -l.

[postgres@ServerName ~]$ psql -p 7432 -l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-------------------+----------------+-----------------+-------------------+-------------------+------------------------+---------------------------+-----------------------
koi8_db | postgres | KOI8R | ru_RU.koi8r | ru_RU.koi8r | | libc |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
py_json_db | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
student | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres + postgres=CRc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres + postgres=CRc/postgres
(6 rows)

Реплика содержит все 6 баз данных с мастер-сервера.

  1. Подключитесь к реплике и попробуйте удалить БД koi8_db.

Подключитесь к реплике.

[postgres@ServerName ~]$ psql -p 7432
psql (15.5)
Type "help" for help.

Попробуйте выполнить DROP DATABASE.

postgres@postgres=# DROP DATABASE koi8_db;
ERROR: cannot execute DROP DATABASE in a read-only transaction

Операция не выполнена — реплика доступна только для чтения.

Подключитесь к мастеру (порт 5432) и удалите БД koi8_db и py_json_db.

postgres@postgres=# \c - - - 5432
You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5432".
postgres@postgres=# DROP DATABASE koi8_db;
DROP DATABASE
postgres@postgres=# DROP DATABASE py_json_db;
DROP DATABASE
  1. Снова подключитесь к реплике и проверьте результат.

Выполните \l на реплике.

[postgres@ServerName ~]$ psql -p 7432 -l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-------------------+----------------+-----------------+-------------------+-------------------+------------------------+---------------------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
student | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres + postgres=CRc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres + postgres=CRc/postgres
(4 rows)

Базы koi8_db и py_json_db исчезли на реплике — изменения с мастера реплицируются автоматически.

  1. Проверьте на мастере состояние слота репликации.

Подключитесь к мастеру.

[postgres@ServerName ~]$ psql

Выполните запрос к представлению.

postgres@postgres=# SELECT * FROM pg_replication_slots \gx
-[ RECORD 1 ]-------+-----------
slot_name | rslot
plugin |
slot_type | physical
datoid |
database |
temporary | f
active | t
active_pid | 66920
xmin |
catalog_xmin |
restart_lsn | 0/AD002648
confirmed_flush_lsn |
wal_status | reserved
safe_wal_size |
two_phase | f

Слот rslot активен (active = t), привязан к процессу с PID 66920.

  1. Проверьте состояние репликации.

Выполните запрос к представлению.

postgres@postgres=# SELECT * FROM pg_stat_replication \gx
-[ RECORD 1 ]-------+-----------
pid | 66920
usesysid | 10
usename | postgres
application_name | walreceiver
client_addr |
client_hostname |
client_port | -1
backend_start | 2024-11-11 14:17:16.098048+03
backend_xmin |
state | streaming|
sent_lsn | 0/AD002648
write_lsn | 0/AD002648
flush_lsn | 0/AD002648
replay_lsn | 0/AD002648
write_lag |
flush_lag |
replay_lag |
sync_priority | 0
sync_state | async
reply_time | 2024-11-11 14:33:22.328724+03

Репликация в режиме streaming, реплика синхронизирована с мастером (replay_lsn = sent_lsn).

  1. Подключитесь к реплике. Повысьте реплику до мастера.

Переподключитесь к реплике.

postgres@postgres=# \c - - - 7432
You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "7432".

Выполните pg_promote().

postgres@postgres=# SELECT pg_promote();
pg_promote
------------
t
(1 row)

Проверьте, что репликация остановлена.

postgres@postgres=# SELECT pg_is_in_recovery();
pg_is_in_recovery
-------------------
f
(1 row)
  1. Подключившись к мастеру, проверьте состояние слота и репликации.

Проверьте слот.

postgres@postgres=# SELECT * FROM pg_replication_slots \gx
-[ RECORD 1 ]-------+-----------
slot_name | rslot
plugin |
slot_type | physical
datoid |
database |
temporary | f
active | f
active_pid |
xmin |
catalog_xmin |
restart_lsn | 0/AD002648
confirmed_flush_lsn |
wal_status | reserved
safe_wal_size |
two_phase | f

Проверьте репликацию.

postgres@postgres=# SELECT * FROM pg_stat_replication \gx
(0 rows)

Репликация разорвана, бывшая реплика теперь — отдельный мастер. Старый мастер тоже в строю.

Самопроверка​

Вопрос 1

Что возвращает функция pg_create_physical_replication_slot('rslot') и какие значения имеет слот пока нет подключенной реплики?

Вопрос 2

Какие параметры автоматически попадают в postgresql.auto.conf после выполнения pg_basebackup -R -S rslot? Выберите все верные варианты.

Вопрос 3

Какая ключевая запись в логе реплики подтверждает переход сервера в режим standby?

Вопрос 4

Какой результат вернет команда DROP DATABASE koi8_db при подключении к реплике?

Вопрос 5

Какие значения имеют поля в pg_replication_slots на мастере, когда реплика подключена? Выберите все верные варианты.

Вопрос 6

Какие ключевые значения содержит pg_stat_replication на мастере при работающей репликации? Выберите все верные варианты.

Вопрос 7

Что происходит после выполнения SELECT pg_promote() на реплике? Выберите все верные варианты.