Расширяемость
Логическая репликация
12
Авторские права
© Postgres Professional, 2020 год.
Авторы: Егор Рогов, Павел Лузанов
Использование материалов курса
Некоммерческое использование материалов курса (презентации,
демонстрации) разрешается без ограничений. Коммерческое
использование возможно только с письменного разрешения компании
Postgres Professional. Запрещается внесение изменений в материалы
курса.
Обратная связь
Отзывы, замечания и предложения направляйте по адресу:
Отказ от ответственности
Компания Postgres Professional не несет никакой ответственности за
любые повреждения и убытки, включая потерю дохода, нанесенные
прямым или непрямым, специальным или случайным использованием
материалов курса. Компания Postgres Professional не предоставляет
каких-либо гарантий на материалы курса. Материалы курса
предоставляются на основе принципа «как есть» и компания Postgres
Professional не обязана предоставлять сопровождение, поддержку,
обновления, расширения и изменения.
2
Темы
Логическая репликация
Публикации и подписчики
Обнаружение и разрешение конфликтов
Особенности работы триггеров
Варианты использования логической репликации
3
Логическая репликация
Механизм
публикующий сервер читает собственные журнальные записи,
декодирует их в изменения строк данных и отправляет подписчикам
сервер-подписчик применяет изменения к своим таблицам
Особенности
публикация-подписчик: поток данных возможен в обе стороны
требуется совместимость на уровне протокола
возможна выборочная репликация отдельных таблиц
При физической репликации только один сервер (мастер) выполняет
изменения и генерирует журнальные записи. Остальные серверы
(реплики) только читают журнальные записи мастера и применяют их.
При логической репликации все серверы работают в обычном режиме,
могут изменять данные и генерировать собственные журнальные
записи. Один сервер может публиковать свои изменения, а другие —
подписываться на них. При этом один и тот же сервер может как
публиковать изменения, так и подписываться на другие. Это позволяет
организовать произвольные потоки данных между серверами.
Сервер-публикатор читает собственные журнальные записи, но не
пересылает их подписчикам «как есть» (как при физической
репликации), а предварительно декодирует их в «логический»,
независимый от платформы и версии PostgreSQL вид. Поэтому для
логической репликации не нужна двоичная совместимость, реплика
должна лишь понимать протокол репликации. Также можно получать и
применять не все изменения, а только отдельных таблиц.
Логическая репликация доступна, начиная с версии 10; более ранние
версии должны были использовать расширение pg_logical
организовывать репликацию с помощью триггеров.
4
Логическая репликация
поставщик
select, insert
update, delete
подписчик
wal sender
сегменты WAL
select, insert
update, delete
сегменты WAL
logical repl.
worker
работает
от имени супер-
пользователя
На рисунке: фоновый процесс logical replication worker на сервере-
подписчике получает информацию от публикующего сервера и
применяет ее. Этот процесс работает от имени суперпользователя,
чтобы иметь доступ ко всем таблицам, участвующим в публикации.
В это же время сервер-подписчик работает обычным образом и
принимает запросы и на чтение, и на запись.
5
Уровни журнала
Параметр wal_level
minimal < replica < logical
восстановление восстановление восстановление
после сбоя после сбоя после сбоя
восстановление восстановление
из резервной копии, из резервной копии,
репликация репликация
логическая
репликация
Чтобы публикующий сервер смог сопоставить собственные
журнальные записи с изменениями табличных строк, в журнале
необходима дополнительная информации. В основном она касается
возможности узнать схему данных любой таблицы в любой момент
времени.
Такой уровень журнала называется logical. На этом уровне в журнал
записывается та же информация, что и на уровне replica, и добавляется
возможность логической репликации.
Поскольку по умолчанию используется уровень replica, значение
параметра wal_level потребуется изменить на публикующем сервере.
6
Публикации и подписчики
Публикующий сервер
публикация включает несколько таблиц одной базы данных
изменения данных выдаются построчно в порядке фиксации транзакций
(реплицируются строки, а не команды SQL)
Подписчики
получают и применяют изменения
возможна начальная синхронизация данных
без разбора, трансформаций и планирования — сразу выполнение
возможны конфликты с локальными данными
Логическая репликация использует модель «публикация — подписчик».
На одном сервере создается публикация, которая может включать ряд
таблиц одной базы данных. Другие серверы могут подписываться на
эту публикацию и получать и применять изменения.
Реплицируются измененные строки таблиц (а не команды SQL).
Команды DDL не передаются, то есть таблицы-приемники на стороне
подписчика надо создавать вручную. Но есть возможность
автоматической начальной синхронизации содержимого таблиц при
создании подписки.
Технически информация об измененных строках извлекается и
декодируется из имеющегося журнала WAL на публикующем сервере,
а затем пересылается процессом wal sender подписчику по протоколу
репликации.
Процесс logical replication worker на подписчике принимает информацию
и применяет изменения.
Применение изменений происходит без выполнения команд SQL и
связанных с этим накладных расходов на разбор и планирование, что
уменьшает нагрузку на подписчика.
8
Конфликты
Режимы идентификации для изменения и удаления
столбцы первичного ключа (по умолчанию)
столбцы указанного уникального индекса с ограничением NOT NULL
все столбцы
без идентификации (по умолчанию для системного каталога)
Конфликты — нарушение ограничений целостности
репликация приостанавливается до устранения конфликта вручную
либо исправление данных,
либо пропуск конфликтующей транзакции
Вставка новых строк происходит достаточно просто. Интереснее
обстоит дело при изменениях и удалениях — в этом случае надо как-то
идентифицировать старую версию строки. По умолчанию для этого
используются столбцы первичного ключа, но при определении таблицы
можно указать и другие способы:
- использовать уникальный индекс (ALTER TABLE … REPLICA IDENTITY
USING INDEX …);
- использовать все столбцы (REPLICA IDENTITY FULL).
- вообще отказаться от поддержки репликации для некоторых таблиц
(REPLICA IDENTITY NOTHING, такой режим по умолчанию установлен
для таблиц системного каталога).
Поскольку таблицы на поставщике и на подписчике могут изменяться
независимо друг от друга, при вставке новых версий строк возможно
возникновение конфликта — нарушение ограничения целостности.
В этом случае процесс применения записей приостанавливается до тех
пор, пока конфликт не будет разрешен вручную. Можно либо исправить
данные на подписчике так, чтобы конфликт не происходил, либо
отменить применение части записей.
10
Триггеры на подписчике
При обычной работе
в обслуживающих процессах (session_replication_role = origin или local)
ENABLE TRIGGER
ENABLE ALWAYS TRIGGER
При применении реплицированных изменений
в процессе logical replication worker (session_replication_role = replica)
ENABLE REPLICA TRIGGER
ENABLE ALWAYS TRIGGER
только на уровне строк (за исключением начальной синхронизации)
Есть особенности в срабатывании триггеров на сервере-подписчике.
При применении изменений, полученных из публикации, обычные
триггеры работать не будут. Это удобно, если на обоих серверах
созданы одинаковые таблицы с одинаковым набором триггеров: в
таком случае триггер уже отработал на публикующем сервере, и его не
надо выполнять на подписчике.
Чтобы триггер все-таки срабатывал, его необходимо разрешить как
репликационный (ALTER TABLE … ENABLE REPLICA TRIGGER) или
универсальный (ENABLE ALWAYS TRIGGER).
Изменения реплицируются построчно, поэтому работают только
триггеры на таблицах на уровне строк (FOR EACH ROW), но не на
уровне оператора (FOR EACH STATEMENT). Исключение составляет
начальная синхронизация — при ней срабатывают и триггеры на
уровне строк, и на уровне оператора.
При обычной работе срабатывают «обычные» триггеры (просто
созданные командой CREATE TRIGGER, или явно разрешенные
командой ALTER TABLE … ENABLE TRIGGER) и универсальные
триггеры (ENABLE ALWAYS TRIGGER).
Сервер отличает обычный процесс от процесса, применяющего
реплицированные изменения, с помощью параметра
sess ion_r eplication_role. По умолчанию параметр равен origin, но
процесс logical replication worker устанавливает его в replica.
12
Консолидация
центральный
сервер
select, insert
update, delete
региональный
сервер
wal sender
региональный
сервер
wal sender
select, insert
update, delete
сегменты WAL
select, insert
update, delete
сегменты WAL
logical repl.
worker
logical repl.
worker
сегменты WAL
получение и консолидация
данных нескольких филиалов
Логическая репликация, как и физическая, позволяет решать разные
задачи.
Например, пусть имеются несколько региональных филиалов, каждый
из которых работает на собственном сервере PostgreSQL, и
необходимо консолидировать часть данных на центральном сервере.
Для решения на региональных серверах создаются публикации
необходимых данных. Центральный сервер подписывается на эти
публикации. Полученные данные можно обрабатывать (например,
приводить к единому виду) с помощью триггеров на стороне
центрального сервера.
Поскольку репликация основана на передаче данных через слот, между
серверами необходимо более или менее постоянное соединение, так
как во время разрыва соединения региональные серверы будут
вынуждены сохранять файлы журнала.
Есть множество особенностей такого процесса и с точки зрения бизнес-
логики, требующих всестороннего изучения. В ряде случаев может
оказаться проще передавать данные пакетно раз в определенный
интервал времени.
13
Общие справочники
центральный
сервер
региональный
сервер
региональный
сервер
сегменты WAL
сегменты WAL
сегменты WAL
репликация справочников
select, insert
update, delete
wal sender
wal sender
select, insert
update, delete
logical repl.
worker
select, insert
update, delete
logical repl.
worker
Другая задача: на центральном сервере поддерживаются справочники,
актуальные версии которых должны быть доступны на региональных
серверах.
В этом случае схему надо развернуть наоборот: центральный сервер
публикует изменения, а региональные серверы подписываются на эти
обновления.
14
Мастер-мастер
основной сервер
основной сервер
select, insert
update, delete
сегменты WAL
select, insert
update, delete
сегменты WAL
wal sender
logical repl.
worker
logical repl.
worker
wal sender
кластер, в котором данные могут изменять несколько серверов
(дело будущего)
Задача: обеспечить надежное хранение данных на нескольких
серверах с возможностью записи на любом сервере (что полезно,
например, для геораспределенной системы).
Для решения можно использовать двунаправленную репликацию,
передавая изменения в одних и тех же таблицах от одного сервера
к другому и обратно.
Сразу заметим, что в настоящее время средства, доступные
в PostgreSQL 12, не позволяют этого реализовать, но со временем эта
возможность скорее всего появится в ядре. В настоящее время более
развитые средства предоставляют расширения pg_logical
Конечно, прикладная система должна быть построена таким образом,
чтобы избегать конфликтов при изменении данных в одних и тех же
таблицах. Например, использовать глобальные уникальные
идентификаторы или гарантировать, что разные серверы работают
с разными диапазонами ключей.
Надо учитывать, что система мастер-мастер, построенная на
логической репликации, не обеспечивает сама по себе выполнение
глобальных распределенных транзакций и, следовательно,
согласованности данных между серверами.
15
Ограничения
Не реплицируются
команды DDL
значения последовательностей
большие объекты (lo)
изменения материализованных представлений, сторонних таблиц,
секционированных таблиц
Могут вызвать проблемы
массовые изменения данных
изменения, сделанные долгими транзакциями
Не поддерживаются
автоматическое разрешение конфликтов
двунаправленная репликация одной и той же таблицы
Логическая репликация имеет довольно много ограничений.
Не реплицируются команды DDL — все изменения схемы данных надо
переносить вручную. До версии 11 не реплицировалась также команда
TRUNCATE. Не реплицируются большие объекты (large objects).
Реплицироваться могут только обычные базовые таблицы. Т. е. нельзя
реплицировать материализованные представления, сторонние и
секционированные таблицы (но можно — отдельные секции).
Не реплицируются значения последовательностей. Это означает, что
если сервер-подписчик добавляет строки в таблицу с суррогатным
уникальным ключом, для которой настроена репликация, возможны
конфликты. Конфликтов можно избежать, выделяя двум серверам
разные диапазоны значений последовательностей, или используя
вместо них универсальные уникальные идентификаторы (UUID).
При выполнении на публикующем сервере одной команды SQL,
затрагивающей много строк, изменения все равно реплицируются
построчно, что приводит к повышенной нагрузке на подписчик.
Текущая реализация не очень хорошо справляется с долгими
транзакциями. Они увеличивают нагрузку на публикующий сервер.
И, как уже говорилось, нет возможности автоматического разрешения
конфликтов и двунаправленной репликации одних и тех же таблиц.
Эти ограничения уменьшают применимость логической репликации.
16
Итоги
Логическая репликация передает изменения строк
отдельных таблиц
разнонаправленная
совместимость на уровне протокола
Следует учитывать имеющиеся ограничения
17
Практика
Мы открываем второй магазин. Он работает независимо
от основного (свой склад, свои закупки и продажи), но имеет
тот же ассортимент.
1. Разверните второй сервер из резервной копии, как показано
в демонстрации. Очистите таблицу операций.
2. Организуйте репликацию справочников книг и авторов
из основного магазина во второй. Предполагается, что эти
таблицы могут меняться только на основном сервере.
Убедитесь, что изменения названий книг и т. п. передаются
на второй сервер, но изменения наличного количества
происходят на двух серверах независимо.
18
Практика
1. На двух серверах ведутся однотипные таблицы
бухгалтерских транзакций. Требуется консолидировать все
записи в ту же таблицу на одном из серверов (например, для
целей построения общей отчетности).
Предложите способ различить «свои» и «чужие» записи и
не допустить конфликты при логической репликации.
Реализуйте предложенную схему.
2. Настройте логическую репликацию произвольной таблицы
в другую на том же самом сервере.
1. Исходите из следующего вида таблицы транзакций:
CREATE TABLE transactions (
trx_id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
debit_acc integer NOT NULL,
credit_acc integer NOT NULL,
amount numeric(15,2) NOT NULL
);
2. Если попробовать выполнить обычные действия, команда CREATE
SUBSCRIPTION «повиснет». Внимательно изучите документацию: