Xpoint
   [напомнить пароль]

Реализация репликации БД master-master

Метки: [без меток]
2008-04-21 14:19:47 [обр] Thirteensmay(0/157)[досье]

Необходимо обеспечить репликацию БД (OracleXE) master-master.
Представляю на суд общественности идеи к реализации сего чуда, буду рад конструктивной критике, в особенности указаниям на недоработки и потенциальные косяки, а также просто предложениям и соображениям в тему. Возможно когото заинтересует и будет время...

Модератору: Прошу не злиться на объем, не представляю как можно короче, удалите если что...


Система репликации БД
идеи к реализации
версия 1

  1. Исходные положения

   Система обеспечивает репликацию соответствующей БД между несколькими базовыми серверами по принципу master-master. Это означает что изменения, внесенные на любом из серверов, автоматически распространяются на все остальные без каких-либо предпочтений, т.е. все сервера в совокупности равнозначны. Репликация выполняется периодически, автоматически, в фоновом режиме и не требует ручного вмешательства.

Система самодостаточна и не требует выделения каких-либо дополнительных средств поддержки, как то например отдельного сервера-контроллера репликации и т.п. Максимальное количество реплицируемых серверов теоретически не ограничено, практически определяется соотношением требований к скорости репликации, объемов реплицируемых данных и скорости каналов связи. К межсерверным каналам связи предъявляются требования разумного постоянства и скорости соответствующей объемам реплицируемой БД, типично 32 .. 512 кбит/сек.

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

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

Под частичным разрешением конфликтов на логическом уровне подразумевается разрешение только общеспецифичных реплицируемым БД конфликтов, обеспечение общей логики возлагается на приложение и не является задачей системы репликации. Специфичные конфликты обусловлены асинхронным характером распространения изменений, к ним например можно отнести следующие: Допустим, реплицируются сервера A, B, C. На сервере A добавляется некоторая новая сущность, после чего она реплицируется на В, и там начинает использоваться, это ее задействование пока не реплицировано обратно на A и там сущность остается свободной. Оператор сервера A в этот момент решает, что сущность была создана по ошибке и корректно ее удаляет, т.к. в его контексте она свободна. Однако при попытке реплицировать удаление на сервер В возможно нарушение целостности. Еще пример: На A и B изменяются одна и та же запись, при репликации этих серверов результат может быть неочевиден. Рассмотренные специфичные конфликты и им подобные разрешаются автоматически, см. далее.

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

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

  1. Общие принципы построения

Логически, система репликации состоит из следующих основных блоков:

- Механизм сбора изменений
- Схема распространения изменений
- Методология разрешения конфликтов

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

   Каждая реплицируемая БД имеет связанный с ней сервис сообщений, по одному на каждую БД. Этот сервис представляет собой независимый от БД процесс ОС, способный взаимодействовать как со своей БД, так и с другими сервисами сообщений. Управление процессом распространения изменений в кластере реплицируемых БД осуществляется совокупностью их сервисов сообщений.

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

Процесс репликации в общем, выглядит следующим образом: На каждом сервере, независимо от других, осуществляется постоянный сбор локальных изменений, относительно предыдущей репликации, и накапливается соответствующий список. Сбор изменений осуществляется самой БД, без участия сервиса сообщений, посредствам триггеров (типа "after insert or update or delete for each row" c целью нейтрализации возможных конфликтов с др. триггерами) на реплицируемых таблицах. Список локальных изменений содержит названия таблиц и атрибуты измененных записей. Здесь необходимо заметить, что несмотря на то что механизм триггеров позволяет контролировать все необходимые изменения, в т.ч. LOB значений, последние например могут вызвать проблемы связанные с объемом информации при хранении передаче и обработке репликационных курсоров. Конкретная структура хранилищ в данном документе не рассматривается и должна быть определена далее в процессе разработки, при этом необходимо учитывать вышеозначенное.

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

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

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

   Особо важным является принцип распространения репликационного курсора между серверами, т.е. последовательность их репликации, определение какой из серверов должен реплицироваться в конкретный момент. Этот принцип учитывает возможность кратковременных нарушений связи, искажений информации при передаче, а также возможность отключения части реплицируемых серверов. Ввиду перечисленных факторов, порядок репликации серверов как таковой не определен, и может быть произвольным, однако условия при которых изменения проходят по всему кластеру соблюдаются. Также учитывается конкурентная природа такого процесса, что реализуется введением понятия состояния сервера – пассивен/активен.

   Инициирование репликации осуществляется сервисами сообщений. Каждый сервис периодически (с помощью планировщика) пытается запустить процесс репликации своего сервера, при этом определен следующий порядок: Сервис устанавливает сервер в состояние активен (предполагается что в промежутках между репликациями серверы находятся в состоянии пассивен). После установки состояния осуществляется запрос ко всем сервисам сообщений кластера на предмет их состояний, если какой либо сервис отвечает состоянием активен то процесс прекращается, и сервер переводится в состояние пассивен. Если все серверы пассивны сервис сообщений запускает процедуру репликации. Таким образом, единовременно, в рамках какой-либо целостной группы кластера (группы состоящей из работающих серверов, имеющих связь друг с другом), может реплицироваться только один сервер.

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

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

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

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

Ситуация прихода ранее обработанного курсора может возникнуть если после предыдущей обработки репликационного курсора на текущем сервере, он еще не перенаправлялся (не был запрошен) другими серверами, и текущий сервер вновь пытается реплицироваться, либо если сервер на который был перенаправлен последний курсор недоступен, либо если на удаленном сервере происходят изменения вне связи с кластером (нейтрализовано особым требованием установки дат использования курсоров, см. выше). Такая ситуация разрешается путем сравнения дат репликационных курсоров – загружаемого с удаленного сервера и локального. Если дата локального курсора позже или равна дате загружаемого то репликация отменяется. При старте репликации кластера курсоры не определены, в этом случае активный сервер получает пустой курсор и наполняет его своим локальным списком изменений.

Идея определения ранее обработанного курсора по дате позволяет в подавляющем большинстве случаев исключить конфликты ранее использованного курсора, а также необоснованную передачу и обработку “лишней” (устаревшей) информации. Однако как рассмотрено далее, в процессе функционирования системы возможны случаи распада кластера на отдельные группы продолжающие независимую репликацию, в таких случаях возможно возникновение “частично ранее обработанных курсоров” (содержащих как уже обработанные записи, так и новые), при этом механизм определения обработанного курсора по дате не может быть применен, т.к. он определяет свойство всего курсора.

Эта проблема решается следующим образом: Частично обработанные курсоры с точки зрения дат являются полностью необработанными, соответственно могут быть приняты и обработаны серверами. С целью избежания конфликтов, содержащиеся в частичных курсорах ранее обработанные записи фильтруются на принимающем сервере перед использование курсора. Фильтрация осуществляется на основе дат изменения записей (определены для каждой в курсоре). Все серверы хранят даты последнего обработанного изменения с каждого другого сервера, что и позволяет выделять только необработанные записи. Т.к. обработка записей идет последовательно по датам, и обновления курсоров разнесены по времени, нахождение двух изменений, одного – ранее обработанного, другого – не обработанного, с одинаковыми датами невозможно.

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

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

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

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

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

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

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

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

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

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

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

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

   Рассмотрим пример функционирования схемы распространения изменений:
   Репликационный кластер состоит из 4 серверов: S1 .. S4 соответственно. На все серверы установлена идентичная копия БД, т.е. кластер полностью синхронизирован. При включении серверов начинается процесс репликации, допустим включаются все серверы, связь при этом надежна. В таком случае репликация начнется с того сервера на котором первым сработает планировщик репликации (допустим это S1). Этот сервер путем установки флага своего состояния заблокирует возможность репликации других серверов и определит используемый репликационный курсор. Т.к. репликация кластера только начинается, ни один из серверов в данный момент не обладает репликационным курсором, таким образом S1 получит пустой курсор, следовательно не внесет в свою БД никаких изменений, но после этого, в результате обновления курсора локальными изменениями, всеже сформирует реальный репликационный курсор, после чего снимет флаг активности и завершит репликацию, разрешив проводить репликацию др. серверам.

   Допустим далее “сработает” S2. Прим. На практике порядок срабатывания серверов произволен, он выполнятся по цепочке определяемой срабатыванием планировщиков, и соображением использования наиболее свежего по дате курсора. Например так: 1-2-3-1-2-4-3. В случае если порядок срабатывания планировщиков определен не циклически каждые N минут, а жестко (например для сервера S1 в 10.00, 10.30, 11.00, сервера S2 в 10.10, 10.40, 11.10 и т.д.), то цепочка может быть идеальной: 1-2-3-4-1-2-3-4…, это повысит эффективность репликации, однако также потребует дополнительных усилий по администрированию или разработке автоматизации. Система в принципе позволяет корректно распространять изменения как в режиме произвольной, так и в режиме жесткой последовательной цепочки, т.к. изначально рассчитана на произвольную передачу. Таким образом режим определяется исключительно и только функционированием планировщиков.

Итак, активизируется сервер S2, он определяет что наиболее свежий репликационный курсор располагается на S1, загружает его, отражает описанные в нем изменения в своей БД, проставляя соответствующие флаги примененности в курсоре, после чего добавляет в курсор свой список локальных изменений, назначает курсору текущую дату, проставляет флаг использования курсора на S1, и завершает репликацию. Сформированный в результате на S2 курсор далее будет использоваться на следующем реплицирующемся сервере. Допустим цепочка репликации 1-2-3-4, в этом случае при репликации S4 все первоначальные записи помещенные в курсор сервером S1 будут применены и на S4 (т.е. на всех серверах), S4 проставит признаки примененности и определит по ним что записи полностью реплицированы в кластере, после чего удалит эти записи из репликационного курсора и создаст соответствующие им в журнале кластерных транзакций. Далее при репликации S1 будут полностью применены и удалены записи первоначально размещенные S2 и т.д. Т.е. цепочка репликации замыкается.

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

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

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

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

   Допустим, целостный кластер штатно реплицируется по цепочке 1-2-3-4, последним реплицировавшимся является сервер S2. В этот момент происходит множественный сбой, таким образом, что связь остается только между серверами S1 и S2, при этом также происходит сбой питания на серверах S2 и S3. В таком состоянии репликация кластера полностью останавливается, т.к. оставшиеся в работе S1 и S4 не имеют связи друг с другом, и находятся в выше описанном состоянии "обрыва связи с работающим сервером" (в моменты репликации не получают удаленных репликационных курсоров/получают пустые, и соответственно просто накапливают изменения в своих репликационных курсорах).

Предположим, что далее восстанавливается питание всех серверов. В этом случае состояние сервера S4 не изменяется, S3 приобретает состояние аналогичное S4, связь у этих серверов по прежнему отсутствует. Сервер S2 включается и т.к. есть связь между S2 и S1 между ними начинается репликация. S2 не может инициировать репликацию т.к. его курсор наиболее молодой (исходя из состояния до сбоя), таким образом репликация между S1 и S2 инициируется S1, этот сервер определяет что его курсор не применен (т.к. был обновлен локальными изменениями когда сервер работал сразу после сбоя без связи с другими), и выполняет репликацию с сохранением последних изменений. Далее репликация между S1 и S2 происходит штатно.

   Следующим шагом становится восстановление связи между S3 и S4 (но не с др. серверами). При этом S3 и S4 также начинают репликацию подобно S1 и S2 (инициатором является S3). В данный момент кластер оказывается в состоянии распада на 2 независимо реплицирующиеся группы: S1 - S2 и S3 - S4. Следующим шагом является восстановление связи между этими группами, т.е. полное возрождение кластера. При этом возможна ситуация образования частично ранее обработанного курсора, т.к. в обоих независимо реплицирующихся группах циркулирует информация как об изменениях произошедших до сбоя, так и о новых изменениях (после сбоя), при этом даты курсоров в этих группах обновляются т.к. они штатно реплицируются. Предугадать в каком направлении пройдет репликация после возрождения кластера в общем случае невозможно. Если это будет от S1 - S2 к S3 - S4, то частично ранее обработанный курсор не образуется, т.к. старые исходя из состояния до сбоя, изменения S1 - S2 не обработаны на S3 - S4, в противном случае доморощенный курсор образуется. В любом случае, как показано выше, частично ранее обработанный курсор обрабатывается системой корректно, и соответственно кластер полностью возрождается.

  1. Разрешение конфликтов

   Как было сказано ранее, система автоматически разрешает возникающие при репликации конфликты, но только на уровне поддержки целостности схемы хранения данных, и общеспецифичные реплицируемым системам. Разрешение таких конфликтов встроено в систему. Однако, в зависимости от конкретной ИС, также возникает требование разрешения конфликтов уровня приложения. Для разрешения таких конфликтов система предлагает специальный интерфейс прикладного разработчика. Таким образом конфликты уровня приложения возможно разрешать дополнительно.

   Интерфейс разрешения конфликтов уровня приложения фактически представляет собой возможность разработки процедур автоматически запускаемых системой непосредственно перед началом применения репликационного курсора. Эти процедуры могут читать и модифицировать курсор в зависимости от текущего состояния БД и требований предъявляемых к разрешению конфликтов. Такой подход позволяет устранить противоречия с существующими в БД триггерами.

   Далее рассматривается разрешение системных конфликтов (на уровне схемы хранения и общеспецифичных) встроенное в систему и выполняемое ею автоматически. В общем случае это:

- Конфликты добавления записей
- Конфликты изменения записей
- Конфликты удаления записей

Системные конфликты добавления записей как таковые отсутствуют. Уникальность значений ключей при добавлении записей обеспечивается в пределах всего кластера путем выделения каждому серверу отдельного диапазона для генерации значений. Диапазон определяется при вводе сервера в кластер и инициализирует соответствующие последовательности. При репликации добавленных записей на другой сервер значения ключей сохраняются, т.к. на исходном сервере на ключи как правило налагается ограничение уникальности, то на целевом сервере конфликты исключены. Возможность повторного добавления (обработки ранее обработанного курсора) записей также исключена схемой распространения изменений.

   При добавлении записей возможны конфликты уровня приложения, например задвоение сущностей. Эти конфликты могут быть разрешены в зависимости от требований конкретной БД прикладным разработчиком с помощью программирования соответствующего интерфейса. Сообщения о таких конфликтах при этом могут быть размещены в журнале кластерных транзакций. Обработка конфликта может заключатся в попытке удаления младшей сущности если она не используется (на нее нет ссылок из связанных таблиц), если младшая сущность используется, то можно попытаться также удалить старшую сущность. Если обе сущности используются то такая ситуация признается автоматически не разрешимой, о чем создается соответствующая запись в журнале кластерных транзакций, при этом разрешение конфликта возлагается на администратора системы. Попытка удаления сущности может быть произведена непосредственно в локальной БД, если она располагается там, либо в противном случае посредствам размещения записи о ее удалении в репликационном курсоре (с соответствующей служебной пометкой этого изменения как вызванного необходимостью разрешения конфликта с целью обеспечения возможности размещения результата попытки разрешения конфликта в журнале транзакций).

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

Системные конфликты удаления записей также возможны. Они связаны с возможным нарушением целостности БД при попытке удаления используемой (связанной) сущности. Естественно что такое удаление не может быть выполнено, в соответствующим образом спроектированных БД это обеспечивается самой СУБД. Однако это не разрешает конфликта, т.к. в распределенной системе на некоторых серверах удаляемая сущность может быть свободна и удалена, а на некоторых нет. Конфликт возникает в процессе применения удаления к серверу на котором сущность используется. Представляется разумным разрешение данного конфликта путем отмены удаления и восстановления удаленной сущности на соответствующих серверах (с последующим в ходе репликации распространением изменений задействующих эту сущность на тех серверах где она свободна). Рассматриваемая система выполняет отмену и откат удаления следующим образом:

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

   Откат удаления осуществляется следующим образом: Сервер который обнаружил конфликт удаления, преобразует соответствующую строку репликационного курсора в строку типа “добавление” в которой проставляет признаки примененности изменения на тех серверах где удаление еще не произошло (определяется исходными признаками примененности), и заполняет строку добавления соответствующими данными из своей БД. Таким образом в ходе дальнейшей репликации кластера удаленные записи будут восстановлены. Также необходимо заметить, что при отмене и откате удалений, в журнал кластерных транзакций помещаются соответствующие сообщения.

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

Powered by POEM™ Engine Copyright © 2002-2005