Двунаправленная репликация как высокотехнологическое шарлатанство

Автор mshurutov, сентября 06, 2016, 10:45:34

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

mshurutov

ЦитироватьДвунаправленная репликация или репликация мастер-мастер, как представляется, по крайней мере по мнению ее сторонников, призвана решить две проблемы -

* Масштабирование
* Обеспечение распределенных вычислений.


Ниже мы постараемся объяснить, почему ни одна из этих целей при использовании двунаправленной репликации не только не достигается, но, наоборот, с ее применением положение дел только ухудшается.
Далее везде предполагается, что существует полная, свободная от любых ошибок, реализация двунаправленной репликации без неочевидных ограничений. Репликация предполагается асинхронной, если не оговорено иное.

       Маcштабирование.
         Запись.

Очевидно, что двунаправленная репликация не может масштабироваться при записи: если у нас есть N узлов в группе взаимнореплицирующихся БД, то каждый узел обязан записать все изменения, произошедшие на всех других узлах; да, он может осуществлять эту запись несинхронно и переупорядочено, что позволяет добиться на узле несколько более высокой пропускной способности, но этот рост по очевидным причинам не может быть безграничным; если коротко, то все, что пишет один сервер, должны как можно быстрее записать и остальные.


         Чтение.

Масштабирование по чтению может быть реализовано, но, к сожалению, чтение это будет неконсистентным - вполне может оказаться так, что один и тот же запрос на всех узлах будет возвращать различные результаты. В ряде случаев это вполне допустимо (например, раздача рекламных баннеров), в ряде случаев - терпимо (новостные сайты, форумы), но для многих задач (от крупного банковского бизнеса  до резервирование мест в солярии) такие несогласованности категорически недопустимы. Более того, если в случае обычной асинхронной однонаправленной репликации в ряде случаев можно добиться консистентного представления на реплике, то в случае двунаправленной репликации это принципиально невозможно. Таким образом, чтение в системе с двунаправленной асинхронной репликацией принципиально неконсистентно.

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


       Обеспечение распределенных вычислений.

Очевидно, что для более-менее распределенных вычислений синхронная репликация не подходит - каждый сбой в сети будет приводить к полной остановке группы взаимнореплицирующихся узлов; таким образом, имеет смысл рассматривать только асинхронную двунаправленную репликацию.
Главной проблемой двунаправленной репликации является отсутствие блокировок на данные: любой узел может менять что угодно; и это вполне может привести к конфликтным ситуациям. Postgres BDR обычно разрешает конфликты по временной метке; это, во-первых, накладывает требование, чтобы сервера были синхронизированы по времени и, во-вторых, нисколько не облегчает ситуацию с собственно конфликтом: если у нас есть учетная система объектов, и в узел №1 приходит требование передать объект X владельцу Y, а в узел №2 приходит требование передать тот же объект X другому владельцу Z, то, во-первых, оба требования будут удовлетворены, а, во-вторых, потом одно из них - неизвестно какое - будет отменено. Совершенно аналогичная ситуация получается и в том случае, когда требуется изъять-добавить некоторый ресурс, не превышая при этом заданного порога, например, клиент может снять все деньги в отделении A и одновременно снять все деньги в отделении Б, в результате чего будет снята сумма, в два раза превышающая допустимую.

Таким образом, реализация распределенных вычислений с помощью двунаправленной репликации требует соблюдения некоторого протокола: для передачи объекта из первого примера узел №1 должен затребовать полное владение этим объектом у других узлов, дождаться от них подтверждения этого (простой записи в таблицу блокировок "объект с id таким-то занят узлом таким-то" недостаточно, так как ровно то же самое может одновременно сделать и другой узел), и уже только после получения такого подтверждения от всех других узлов выполнить требуемую операцию; совершенно аналогично требуется поступать и в примере со снятем денег - сначала отделение должно потребовать от других отделений полного доступа к данным клиента, произвести списание и уведомить другие узлы о том, что клиент доступен снова. К сожалению, в вышеприведенном примере сбой одного узла приводит к полной блокировке всех операций модификации - и даже не в этом узле, просто от узла B узел A не может дождаться подтверждения и потому не может произвести требуемую операцию. Таким образом, одно обновление/вставка строки влечет за собой N-1 вставок при блокировке ресурса и N-1 удалений - при освобождении блокировки; если N при этом достаточно велико, то ресурсы, требуемые для обеспечения блокировки окажутся на порядок (или даже на порядки) больше, чем требуемая операция; следовательно, не может быть и речи о том, чтобы иметь десятки или тем более сотни и тысячи взаимнореплицирующихся серверов.

Добавление - удаление узлов с соблюдением вышеописанного протокола также достаточно нетривиально.

Из сказанного можно видеть, что двунаправленная репликация используется в описанных сценариях исключительно как транспорт и, что хуже, 1) порождает дополнительную нагрузку - так, блокировка одного клиента с помощью двунаправленной репликации потребует N-1 операций добавления строк на каждом из N узлов (каждый узел пишет подтверждение неблокирования в таблицу неблокировок (сервер X подтверждает, что он отдает данные клиента Y серверу Z), а снятие - N-1 операций удаления - вот такое вот чудо получается) и 2) сбой одного узла блокирует все запросы на модификацию.


       Выводы

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

Отседова, однако
С уважением, PostgreSQL DBA
Шурутов Михаил.