[Перевод] Логическая репликация между версиями PostgreSQL

ylprhs3ilpoukerjhyvwdnj6kmu.png

Есть разные подходы к обновлению PostgreSQL, но некоторые приводят к простою приложения. Если нужно избежать простоя, используйте для обновления репликацию — логическую или физическую (потоковую), в зависимости от сценария. В этой статье мы рассмотрим разницу между логической и физической репликацией в PostgreSQL. Затем подробно поговорим, как обновить версию с помощью логической репликации и при этом избежать простоя приложения. В следующей статье обсудим репликацию физическую.

В предыдущих статьях мы уже говорили о методах обновления PostgreSQL (Обновление версии PostgreSQL с помощью pg_dumpall и Обновление версии PostgreSQL с помощью pg_dump/pg_restore) в рамках серии Обновление или миграция старых версий PostgreSQL в новые. Но оба этих метода не исключают простоя.


Типы логической репликации

Здесь мы обсудим 2 типа репликации:


  • Репликация между PostgreSQL 10 и 11 с помощью встроенной логической репликации.
  • Репликация между PostgreSQL 9.4 (или до PG 11) и PostgreSQL 11 с помощью расширения pglogical.

Чтобы минимизировать простой, можно обновить версию с помощью репликации. Когда все актуальные данные будут реплицированы на другой сервер PostgreSQL последней версии, вы просто переведете приложение на новый сервер с минимальным простоем — хотя, конечно, все зависит от сложности стека приложения.

Логическая репликация в PostgreSQL позволяет пользователям выборочно реплицировать таблицы и открыть резервный сервер для операций записи. Физическая репликация в PostgreSQL осуществляется блоками. В этом случае каждая база данных в мастере реплицируется на резервный сервер, недоступный для операций записи. Далее мы будем называть физическую репликацию потоковой.

При использовании логической репликации на резервном сервере можно включить репликацию с нескольких мастеров. Это бывает полезно в ситуациях, когда нужно реплицировать данные из нескольких баз данных PostgreSQL (OLTP) на один сервер PostgreSQL для отчетности и хранения данных.

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


Репликация между версиями PostgreSQL 10 и 11

Начиная с PostgreSQL 10 логическая репликация доступна по умолчанию. Поэтому вы легко реплицируете базу данных PostgreSQL 10 в PostgreSQL 11. При логической репликации используется модель публикации и подписки. Узел, отправляющий изменения, становится издателем. А узел, подписывающийся на эти изменения, становится подписчиком. На одну публикацию может быть несколько подписок.


Публикация

Публикация — это массив изменений, созданных группой таблиц. Она называется набором изменений или набором репликации. Публикации могут содержать только таблицы, но не другие объекты. DML в этих таблицах реплицировать можно, а DDL — нельзя.

В публикации можно выбрать, DML какого типа реплицировать: INSERT, DELETE, UPDATE или ALL. По умолчанию выбрано ALL. У таблицы должен быть идентификатор реплики, чтобы реплицировать подписчику операции UPDATE и DELETE. Идентификаторы реплики помогают находить строки, которые обновляются или удаляются.

Первичный ключ таблицы — это идентификатор реплики по умолчанию. Или вы можете сделать идентификатором уникальный индекс со значениями NOT NULL. Если у вас нет первичного ключа или уникального индекса со значениями NO NULL, установите для replica_identity значение FULL. В таком случае Postgres использует всю строку в качестве ключа. Но это не очень рационально.

Если таблица без первичного ключа и идентификатора реплики по умолчанию добавляется в публикацию после операции UPDATE или DELETE, могут возникнуть ошибки.


Подписка

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


Пример логической репликации

В следующем примере описывается логическая репликация только между версиями PostgreSQL 10 и 11.

Создайте публикацию на узле-издателе. Добавьте в публикацию все или только некоторые таблицы.

-- For adding ALL Tables in Database
CREATE PUBLICATION percpub FOR ALL TABLES;

-- For adding Selected Tables in Database
CREATE PUBLICATION percpub FOR TABLE scott.employee scott.departments;

На узле-подписчике создайте подписку на эту публикацию. Выполните DDL-дамп таблиц подписчику, прежде чем создать подписку, как говорилось выше.

$ pg_dump -h publisher_server_ip -p 5432 -d percona -Fc -s -U postgres | pg_restore -d percona -h subscriber_node_ip -p 5432 -U postgres
CREATE SUBSCRIPTION percsub CONNECTION 'host=publisher_server_ip dbname=percona user=postgres password=secret port=5432' PUBLICATION percpub;

Эта команда также копирует существующие данные в таблицах. Если нужно отключить копирование существующих данных, используйте следующую команду, и будут копироваться только изменения в издателе.

CREATE SUBSCRIPTION percsub CONNECTION 'host=publisher_server_ip dbname=percona user=postgres password=oracle port=5432' PUBLICATION percpub WITH (copy_data = false);

Отслеживайте репликацию с помощью следующей команды в узле-издателе:

$ psql
\x
select * from pg_stat_replication;


Репликация между PostgreSQL 9.4 и PostgreSQL 11

Что делать с версиями до PostgreSQL 10? Для версий с 9.4 по 11 есть специальное расширение — pglogical. С помощью pglogical можно в два счета реплицировать PostgreSQL 9.4 в PostgreSQL 11.

Ниже приводятся общие инструкции по настройке репликации между PG 9.4 и PG 11 с помощью расширения pglogical.

Шаг 1. Считайте, что pgserver_94 — это исходный сервер с базой данных percona_94 на PostgreSQL 9.4. Создайте следующее расширение.
код

[pgserver_94:] $psql -d percona_94 -c "CREATE EXTENSION pglogical_origin"
CREATE EXTENSION
[pgserver_94:] $psql -d percona_94 -c "CREATE EXTENSION pglogical"
CREATE EXTENSION

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

[pgserver_94:] $psql -d percona_94
psql (9.4.21)
Type "help" for help.
percona_94=# SELECT pglogical.create_node(node_name := 'provider1',dsn := 'host=192.168.0.24 port=5432 dbname=percona_94');
create_node
-------------
2976894835
(1 row)
percona_94=# SELECT pglogical.replication_set_add_all_tables('default', ARRAY['public']);
ERROR: table pgbench_history cannot be added to replication set default
DETAIL: table does not have PRIMARY KEY and given replication set is configured to replicate UPDATEs and/or DELETEs
HINT: Add a PRIMARY KEY to the table
percona_94=# ALTER TABLE pgbench_history ADD PRIMARY KEY (tid,aid,delta);
ALTER TABLE
percona_94=# SELECT pglogical.replication_set_add_all_tables('default', ARRAY['public']);
replication_set_add_all_tables
--------------------------------
t
(1 row)

Шаг 3. На узле-подписчике, то есть в базе данных PostgreSQL 11, выполните следующие команды.

[pgserver_11:] $psql -d percona_11
psql (11.2)
Type "help" for help.
percona_11=# SELECT pglogical.create_node(node_name := 'subscriber1',dsn := 'host=127.0.0.1 port=5432 dbname=percona_11 password=secret');
 create_node
-------------
   330520249
(1 row)
percona_11=# SELECT pglogical.create_subscription(subscription_name := 'subscription1',provider_dsn := 'host=192.168.0.24 port=5432 dbname=percona_94 password=secret');
 create_subscription
---------------------
          1763399739
(1 row)

Шаг 4. Затем проверьте статус репликации, отправив запрос в несколько таблиц, которые pglogical всегда обновляет:

percona_11=# select * from pglogical.local_sync_status;
 sync_kind | sync_subid | sync_nspname |   sync_relname   | sync_status | sync_statuslsn
-----------+------------+--------------+------------------+-------------+----------------
 f         | 1763399739 | public       | pgbench_accounts | r           | 0/2EB7D48
 f         | 1763399739 | public       | pgbench_history  | r           | 0/2EB7D48
 f         | 1763399739 | public       | pgbench_tellers  | r           | 0/2EB7D48
 f         | 1763399739 | public       | pgbench_branches | r           | 0/2EB7D48
 d         | 1763399739 |              |                  | r           | 0/0
(5 rows)
percona_11=# select * from pglogical.subscription;
   sub_id   |   sub_name    | sub_origin | sub_target | sub_origin_if | sub_target_if | sub_enabled |             sub_slot_name              |         sub_rep
lication_sets          | sub_forward_origins | sub_apply_delay
------------+---------------+------------+------------+---------------+---------------+-------------+----------------------------------------+----------------
-----------------------+---------------------+-----------------
 1763399739 | subscription1 | 2976894835 |  330520249 |    2402836775 |    2049915666 | t           | pgl_percona_11_provider1_subscription1 | {default,defaul
t_insert_only,ddl_sql} | {all}               | 00:00:00
(1 row)


Выбор первичного ключа

На втором шаге вы видели, как все таблицы схемы public добавились в набор репликации путем создания первичного ключа для таблицы, у которой его не было. Возможно, я выбрал неправильный первичный ключ для этой таблицы, но это просто для демонстрации. Когда будете выбирать первичный ключ, убедитесь, что он правильный. Он должен быть уникальным и использовать столбцы, которые не содержат значения NULL. Если не найдете правильный первичный ключ, это может привести к простою приложения. Вот пример ошибки, которая может возникнуть:

[pgserver_94:] $pgbench -c 10 -T 300 -n percona_94
Client 7 aborted in state 12: ERROR: duplicate key value violates unique constraint "pgbench_history_pkey"
DETAIL: Key (tid, aid, delta)=(7, 63268, 2491) already exists.

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

© Habrahabr.ru