Алгоритм
асинхронной репликации

 

 

Автор: Марат Губаев (Marat  Gubaiev)

Дата создания ‑ 17.11.2006. Дата редактирования ‑ 03.11.2007.

Частичная или полная публикация возможна только при наличии ссылки на http://repl2.narod.ru .

Контакты: gubayev@yandex.ru

 

В статье рассматривается алгоритм асинхронной репликации собственного изобретения. Алгоритм предназначен для построения РБД с произвольной топологией.

Работоспособность алгоритма демонстрируется с помощью прототипа (см. DOWNLOADS).

 

БЛАГОДАРНОСТИ

д.т.н., доценту, проф. кафедры 603 ХАИ Туркину Игорю Борисовичу за постановку задачи и мудрое руководство дипломным проектом;

Тимуру Губаеву за редактирование, поиск источников и поддержку;
Кириллу Толстолужскому за ценные замечания.

 

ОГЛАВЛЕНИЕ

СПИСОК УСЛОВНЫХ ОБОЗНАЧЕНИЙ И СОКРАЩЕНИЙ.. 3

1 Зачем ещё один алгоритм репликации?. 4

2 Поставленная задача.. 5

2.1 Характеристики РБД.. 5

2.2 Характеристики прототипа.. 5

3 Основные принципы ЛБД.. 6

3.1 Составной ключ, запакованный в 64-х разрядное число.. 6

3.2 Использование счётчика поколений для регистрации изменений.. 6

3.3 Служебные таблицы для регистрации изменений.. 7

3.4 Двухэтапная установка поколений.. 8

3.4.1 Описание проблемы.. 8

3.4.2 Примеры.. 8

3.4.3 Преимущества двухэтапной установки поколений. 9

3.5 Типы транзакций. Состояния триггеров. 10

4 Дополнительные принципы ЛБД.. 11

4.1 Разрешение конфликтов обновления.. 11

4.1.1 Описание проблемы.. 11

4.1.2 Предложенное решение. 11

4.1.3 Альтернативы.. 12

4.2 Очистка таблиц регистрации.. 12

4.2.1 Описание проблемы.. 12

4.2.2 Предложенное решение. 12

4.2.3 Альтернативы.. 12

5 Порядок репликации.. 13

5.1 Описание алгоритма репликации.. 13

5.2 Листинг метода TInteractionDM.Receive (реализация алгоритма репликации) 14

6 Резюме. 17

6.1 Основные принципы... 17

6.2 Преимущества.. 17

6.3 Недостатки.. 17

Список источников.. 18

Ссылки.. 18

Статьи. 18

Описание алгоритмов. 18

Описание продуктов. 18

Другие статьи. 19

Дискуссии на форумах. 19

Продукты.. 20

Другие ссылки. 20

Литература.. 20

ПРИЛОЖЕНИЕ. DOWNLOADS.. 21

СПИСОК УСЛОВНЫХ ОБОЗНАЧЕНИЙ И СОКРАЩЕНИЙ

БД – база данных.

Асинхронная репликация (далее просто «репликация») – синхронизация изменений в двух БД.

РБД – распределённая БД. В статье термин «РБД» понимается не строго (12 условий Дейта для РБД не выполняются). Под РБД понимается множество БД имеющих одинаковую структуру таблиц и передающих друг другу данные в процессе репликации.

ЛБД – БД в составе РБД. Может получать данные от других ЛБД и передавать данные другим ЛБД в составе РБД.

Сервер – ЛБД, передающая данные.

Клиент – ЛБД, принимающая  данные.

1 Зачем ещё один алгоритм репликации?

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

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

Репликаторов много, а описаний алгоритмов мало.

2 Поставленная задача

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

2.1 Характеристики РБД

В данной статье рассматривается РБД со следующими характеристиками.

1.     Произвольная топология: ЛБД могут быть связаны произвольным образом (в т.ч. циклически).

2.     Запись изменяется и удаляется только в той ЛБД, в которой была создана (схема ведущий-ведомый).

3.     Возможно одновременное внесение изменений, приём данных от нескольких серверов и считывание данных несколькими клиентами, так же одновременная репликация двух ЛБД друг с другом и одновременное выполнение служебных транзакций (установка поколений, очистка логов).

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

2.2 Характеристики прототипа

Прототип реализован на Delphi7+FireBird1.0. Основная логика реализована с помощью триггеров и хранимых процедур FireBird. В Delphi вынесен только собственно алгоритм репликации, т.к. он предполагает взаимодействие 2х ЛБД.

ЛБД прототипа состоит из 2х таблиц, связанных отношением главная-подчинённая

3 Основные принципы ЛБД

3.1 Составной ключ, запакованный в 64-х разрядное число

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

В данном алгоритме используется вычисление первичного ключа про формуле. Для хранения первичного ключа используется 64-разрядное число (NUMERIC(18,0)). Старшие 4 байта – ID ЛБД, младшие 4 байта ‑ ID записи. Фактически это – составной ключ, записанный в одно поле. Таким образом, первичные ключи в синхронизируемых таблицах должны быть одного типа ‑ NUMERIC(18,0).

3.2 Использование счётчика поколений для регистрации изменений

Обычное «человеческое» решение – использовать для регистрации изменений временные метки (time stamp). Но у временных меток есть множество недостатков:

-       очень трудно установить одинаковое время на всех узлах РБД;

-       системное время зависит от человеческого фактора: его можно выставить как угодно;

-       разнообразные системы времени: UTC, поясное время и т.д.;

-       разнообразные способы представления времени в компьютере: в каждой OS, СУБД, языке программирования может быть своё представление времени, с разной точностью и ограничениями;

Из всего этого следует, что time stamp лучше по возможности не использовать. Вместо time stamp будем применять аналог логического таймера (logical clock)[entropy6.pdf], который я назвал счётчиком поколений. В [entropy6.pdf] значение logical clock увеличивается после каждого события (в данном случае событие ‑ изменение), таким образом, можно восстановить очерёдность изменений в одной ЛБД, но нельзя восстановить очерёдность изменений в РБД, т.к. нельзя сравнивать значения logical clock в разных ЛБД. Счётчик поколений отличается от logical clock тем, что поколения увеличиваются в общем случае после нескольких изменений. Тогда эти изменения принадлежат одному поколению.

3.3 Служебные таблицы для регистрации изменений

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

1.     Каждой таблице с данными XXXX соответствует одна таблица регистрации LOG_XXXX.

2.     Каждой записи в таблице регистрации соответствует одна запись в таблице данных, если запись вставлялась или изменялась;

3.     Записи в таблице регистрации не соответствует ни одной записи в таблице данных, если запись удалена.

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

 Таблица регистрации LOG_XXXX имеет следующий вид (XXXX – соответствующая таблица данных):

Назначение

Физическое имя

Примечание

ID записи

LOG_GID

 

Поколение вставки

LOG_INS_GEN

 

Поколение изменения/удаления

LOG_UPD_GEN

 

Признак удалённости

LOG_IS_DELETED

Если нет подчинённой записи в таблице данных, значит, признак удалённости равен True(1), иначе – False(0)

ID ЛБД-владельца записи (ЛБД, в которой запись была создана)

LOG_DB_ID

Вычисляется по ID записи LOG_GID.

3.4 Двухэтапная установка поколений

3.4.1 Описание проблемы

Поколения записи устанавливаются в два этапа.

1-й этап. При вставке LOG_INS_GEN и LOG_UPD_GEN устанавливаются в NULL. При изменении или удалении записи LOG_UPD_GEN устанавливается в NULL. Эта запись становится невидимой для клиентов.

 

LOG_INS_GEN

LOG_UPD_GEN

Insert

NULL

NULL

Update

 

NULL

Delete

 

NULL

2-й этап. Периодически запускается транзакция, в которой счётчик поколений увеличивается на 1. Новое значение счётчика заносится в LOG_INS_GEN и LOG_UPD_GEN, если эти поля были установлены в NULL. Клиенты получают эту запись во время репликации. Важно, что бы поколения не выставлялись более чем в одной транзакции одновременно. Двухэтапная установка поколений позволяет избежать «скрытия» данных при репликации.

3.4.2 Примеры

Рассмотрим следующий пример (см. порядок репликации)

1.     Транзакция T1 изменяет запись R1. Устанавливает поколение записи g.

2.     Транзакция T2 изменяет запись R2. Устанавливает поколение записи g+1.

3.     T2 подтверждается.

4.     Клиент узнаёт об изменениях в записи R2. Запоминает, что поколение на сервере равно g+1.

5.     T1 подтверждается.

Клиент не узнает об изменениях в записи R1, т.к. считается, что если клиент знает об изменениях в поколении g+1, то он знает и об изменениях в поколении g (с time stamp была бы аналогичная проблема).

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

1.     Транзакция T1 изменяет запись R1. Устанавливает поколение записи в NULL.

2.     Транзакция T2 изменяет запись R2. Устанавливает поколение записи в NULL.

3.     T2 подтверждается.

4.     Запись R2 скрыта для клиентов.

5.     T1 подтверждается.

6.     Транзакция Tg устанавливает поколение g для записей R1 и R2.

7.     Клиент узнаёт об изменениях в записях R1, R2. Запоминает, что поколение на сервере равно g.

Клиент узнаёт обо всех изменениях.

3.4.3 Преимущества двухэтапной установки поколений.

1.     Т.к. поколение устанавливается только для подтверждённых изменений, то при репликации сохраняется целостность транзакций, т.е. все изменения, произошедшие в одной транзакции, передадутся за одну репликацию.

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

3.5 Типы транзакций. Состояния триггеров.

Транзакции в ЛБД можно разделить на три типа.

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

2.     Служебные транзакции – транзакции, запускаемые фоновыми процессами (очистка логов (CLEAR_DEL_LOGS), установка поколений (SET_NEW_GEN)). Данные не меняются, следовательно, триггеры таблиц данных не вызываются. Меняются только таблицы регистрации.

3.     Транзакции репликации – выполняют репликацию, в ЛБД применяются изменения полученные из другой ЛБД (PROCESS_INPUT_TABLES). Триггеры таблиц данных находятся в состоянии репликации. Состояние репликации включается процедурой BEGIN_RECEIVE и отключается процедурой END_RECEIVE. В этом состоянии триггеры не изменяют таблицы данных, с помощью триггеров изменяются только таблицы регистрации.

4 Дополнительные принципы ЛБД

4.1 Разрешение конфликтов обновления

4.1.1 Описание проблемы

Несмотря на то, что запись изменяется только в той ЛБД, где она была создана, конфликты обновления всё равно могут возникнуть, если ЛБД получает запись несколькими путями.

Рассмотрим пример.

1.     ЛБД A создала запись R

2.     ЛБД B и C реплицировались с A и получили запись R

3.     ЛБД A изменила запись R

4.     ЛБД B реплицировалась с A, получила новую версию R

5.     ЛБД B реплицировалась с C, получила старую версию R

4.1.2 Предложенное решение

Для разрешения конфликтов к таблице с данными добавляется поле LOG_OWN_GEN – собственное поколение записи. Т.е. поколение записи, в котором она была вставлена или изменена. Тогда в случае конфликтов проверяются версии  и применяются только новые изменения.

Теперь предыдущий пример будет выглядеть следующим образом.

1.     ЛБД A создала запись R(LOG_OWN_GEN=1)

2.     ЛБД B и C реплицировались с A и получили запись R(LOG_OWN_GEN=1)

3.     ЛБД A изменила запись R(LOG_OWN_GEN=2)

4.     ЛБД B реплицировалась с A, получила новую версию R(LOG_OWN_GEN=2)

5.     ЛБД B реплицировалась с C, получила старую версию R(LOG_OWN_GEN=1). Изменение не применяется, т.к. ЛБД B имеет новую версию записи R с собственным поколением равным 2 (LOG_OWN_GEN=2).

4.1.3 Альтернативы

Возможно, например, позволить всем ЛБД изменять запись и принимать самые поздние изменения. Удалять сможет только владелец записи. Или принимать изменения от ЛБД с наибольшим приоритетом и т.д.

4.2 Очистка таблиц регистрации

4.2.1 Описание проблемы

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

4.2.2 Предложенное решение

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

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

4.2.3 Альтернативы

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

В случае, если список клиентов фиксированный, можно обойтись без уведомлений от клиента. Сервер сам узнает у клиента, что клиент знает о нём.

5 Порядок репликации

5.1 Описание алгоритма репликации

(Реализовано в TInteractionDM.Receive)

БД, которая получает данные, назовём клиентом.

БД, с которой данные считываются, назовём сервером.

Репликация начинается по инициативе клиента.

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

1.     Запросить текущее состояние счётчика поколений сервера (Server.CURR_GEN)

2.     Для каждого поколения начиная от известного поколения сервера + 1 (Выбрать из DB_PROFILE) до Server.CURR_GEN (изменения неизвестные клиенту) выполнить:

a.      Стартовать транзакцию; установить состояние репликации (Client.BEGIN_RECEIVE)

b.     Принять изменения с сервера (Server.DB_ID_GEN, Server.MASTER_GEN, Server.DETAIL_GEN); изменения запоминаются в буферных таблицах (Client.DB_PROFILE_INPUT, Client.MASTER_INPUT, Client.DETAIL_INPUT).

c.     Применить изменения (Client.PROCESS_INPUT_TABLES):

                                                                                     i.      обновление (порядок главная-подчинённая),

                                                                                   ii.      вставка (порядок главная-подчинённая),

                                                                                 iii.      удаление (порядок подчинённая-главная).

d.     Отключить состояние репликации, запомнить поколение сервера(Client.END_RECEIVE); подтвердить транзакцию

e.      Установить новое поколение (Client.SET_NEW_GEN); установка поколения выполняется в специальной транзакции.

В случае исключительной ситуации репликацию можно продолжить с последнего успешно принятого поколения, а не сначала.

Также в реализации сервер запоминает, какое поколение принял клиент (Server.SET_CLIENT_GEN). Это нужно для очистки логов от мёртвых записей. За исключением вызова Server.SET_CLIENT_GEN данные передаются только от сервера клиенту.

5.2 Листинг метода TInteractionDM.Receive (реализация алгоритма репликации)

 

(*********************************************************************)

(*получить данных с сервера FileName                                 *)

(*может возбуждать исключение EAbort                                 *)

(*********************************************************************)

procedure TInteractionDM.Receive(const FileName: string);

  var

    Server_CurrGen:   Integer;

    Client_ServGen:   Integer;

    gen:              Integer;

  begin

    ServerMainDM.Open( FileName );

    //Предполагается, что уже вызван метод ClientMainDM.Open

    try

      //БД не может принимать данные, если запись о текущей БД (IS_CURR = 1)

      //удалена из DB_PROFILE

      if ClientMainDM.Deleted then

       begin

         ShowMessage( 'DB is deleted' );//TODO: заменить на своё исключение

         ABORT;

       end;

 

      Server_CurrGen   := ServerMainDM.GetCurrGen;//Текущее поколение на сервере. Вызов CURR_GEN на сервере в отдельной транзакции

      Client_ServGen   := ClientMainDM.GetServGen( ServerMainDM.GetCurrDBID );//Поколение сервера о котором клиент уже знает. Select из DB_PROFILE на клиенте в отдельной транзакции. TODO: заменить select на хранимую процедуру

      //Уведомить сервер, что клиент принял поколение Client_ServGen

      //(на случай, если во время предыдущей репликации уведомить сервер не получилось,

      // и новых данных на сервере не появилось (цикл выполнятся не будет) )

      //Эта информация используется сервером при очистке логов

      //Вызов SET_CLIENT_GEN на сервере

      ServerMainDM.SetClientGen( ClientMainDM.GetCurrDBID, Client_ServGen );

      for gen := Client_ServGen + 1 to Server_CurrGen do

        begin

          StartReceive( gen );//Начать приём поколения gen. Вызов BEGIN_RECEIVE

          try

            ReceiveDBID( gen );//Принять изменения в DB_PROFILE (заполнить DB_PROFILE_INPUT). Вызов DB_ID_GEN на сервере

            (******Scema specific*****)

            ReceiveMaster( gen );//Принять изменения в MASTER (заполнить MASTER_INPUT). Вызов MASTER_GEN на сервере

            ReceiveDetail( gen );//Принять изменения в DETAIL (заполнить DETAIL_INPUT). Вызов DETAIL_GEN на сервере

            (******/Scema specific****)

            ApplyReceivedData;//Применить изменения(используются таблицы XXX_INPUT). Вызов PROCESS_INPUT_TABLES

            if Assigned( OnBeforeCommitReceiveGen ) then

              OnBeforeCommitReceiveGen( Self, gen );//В Replication.exe реализовано как запрос пользователю подтвердить или откатить транзакцию,

                                                    //если пользователь выбрал откатить, то в обработчике вызывается ABORT

                                                    //(запрос работает при отмеченной опции Confirm Receive).

 

            CommitReceive;//Подтвердить приём данных (транзакции подтверждаются). Вызов END_RECEIVE

 

            //После приёма данных нужно установить новое поколение (вызов SET_NEW_GEN на клиенте)

            //Реализовано в обработчике как посылка сообщения методом post приложению Backgrounds.exe

            if Assigned( OnAfterCommitReceiveGen ) then

              OnAfterCommitReceiveGen( Self, gen );

          except

            RollbackReceive;//Отменить приём данных (транзакции откатываются)

            raise;

          end;

          //Уведомить сервер, что клиент принял поколение gen

          //Эта информация используется сервером при очистке логов

          //Вызывается ПОСЛЕ того как клиент принял данные.

          //Вызов SET_CLIENT_GEN на сервере

          ServerMainDM.SetClientGen( ClientMainDM.GetCurrDBID, gen );

        end;(*for*)

    finally

      ServerMainDM.Close;

    end;(*try*)

  end;

6 Резюме

6.1 Основные принципы

-       генерация уникального первичного ключа по формуле;

-       вместо системного таймера используется счётчик поколений;

-       регистрация изменений с помощью двухэтапной установки поколений.

6.2 Преимущества

-       ключи не преобразовываются;

-       простой алгоритм регистрации изменений;

-       при передаче данные естественным образом разбиваются на блоки;

-       при передаче данных сохраняется целостность транзакций.

6.3 Недостатки

-       первичный ключ должен быть 64-разрядным числом (в InterBase/FireBird ‑ NUMERIC(18, 0));

-       для каждой ЛБД должен быть запущен специальный процесс – установщик поколений;

-       невозможен одновременный приём одинаковой записи с разных серверов.

Список источников

Источники, которые использовались при написании статьи особо часто, выделены жирным шрифтом. Источники, наиболее важные с точки зрения статьи, выделены жирным шрифтом и подчёркиванием

Ссылки

Статьи

Описание алгоритмов

1.          Статья «Репликация данных между центром и удалёнными филиалами» (IB), автор Igor Ilyinsky http://home.sinn.ru/~mapnn/articles.html

2.          Статья «Практическая репликация», авторы Андрей Луковенко, Айрат Фаритов http://www.osp.ru/os/2001/12/045.htm

3.          Статья «Репликация базы данных» (IB), автор: Евдокимов Алексей http://replication.chat.ru

4.          Статья «Understanding Replication in Databases and Distributed Systems» www.cs.mcgill.ca/~kemme/papers/icdcs00.pdf

5.          Статья «Тиражирование электронных каталогов библиотек», авторы Копытков Д.Ю., Цой К.В., Карауш А.С., Кравчук С.С. http://ask.tomsk.ru/files/tusur-05-reli.pdf

6.          Статья «СУБД ЛИНТЕР. Технический обзор»: http://citforum.novgorod.ru/database/linter/overview/rel12.shtml

Описание продуктов

7.          Статья «Автоматическое управление диапазонами Identity в репликации слиянием» (MSSQL) http://www.sql.ru/articles/mssql/03100903AutomaticallyAssignIdentityRangeForSubscription.shtml

8.          Репликация в MSSQL («шпаргалка») http://www.sql.ru/subscribe/70028/10.shtml

9.          Статья «Репликация распределенной БД Oracle» http://katori.pochta.ru/oracle.html

10.      Кратко о репликации в Oracle: http://www.omega.ru/example/example9.html

11.      «Выбор способа синхронизации (MDB)».(MS Access).http://office.microsoft.com/ru-ru/assistance/HP052623361049.aspx

12.      Статья «Репликация данных в PostgreSQL» http://www.opennet.ru/links/info/1084.shtml

13.      Статьи по репликации в MS SQL Server на www.sql.ru http://www.sql.ru/articles/Publications.shtml#13

14.      Обзор статьи "Database Replication" DBMS, vol.10, N 5, May 1997, www.dbmsmag.com, автор обзора С. Кузнецов (MSSQL, Oracle, Sybase) http://citforum.amursu.ru/database/digest/dig_1606.shtml

15.        «Database Replication», автор Charles Thompson: http://www.dbmsmag.com/9705d15.html

16.      Описание системы DBSync. http://www.relex.ru/dbsync_rus.php

17.      FAQ по SybaseASA http://www.sql.ru/faq/faq.aspx?id=173

18.      Презентация, описывает методы репликации, упоминает термин поколения (generation) http://research.microsoft.com/~gray/WICS_99_TP/18_Philbe%20Replication%20Stanford99.ppt

Другие статьи

19.      Статья «Транзакции в InterBase», автор Кузьменко Дмитрий: http://www.ibase.ru/devinfo/ibtrans.htm

20.      Статья «Естественные ключи против искусственных ключей», автор Анатолий Тенцер: http://www.akzhan.midi.ru/devcorner/articles/NaturalKeysVersusAtrificialKeysByTentser.html

21.      Лекция «Базисные средства манипулирования реляционными данными» http://ergeal.ru/txt/archive/cs/db/glava5.htm#_2_2_1

22.      Учебное пособие «Введение в системы управления базами данных»: http://www.citforum.ru/database/dblearn/

23.      Статья по репликации, описание логических таймеров (logical clock) www.cs.duke.edu/~chase/cps212-archive/slides/entropy6.pdf

24.      Проблемы с безопасностью при использовании генератора случайных чисел, основанного на таймере http://lnfm1.sai.msu.ru/~leo/rand.html

25.      Статья «The Dirty Little Secret Of Asynchronous Replication», автор Boaz Palgi: http://www.techworld.com/files/whitepapers/Topio%20Dirty%20Little%20Secret.pdf

Дискуссии на форумах

26.      Дискуссия о репликации (MySQL) http://forums.mysql.com/read.php?24,53048,53048

27.      Обсуждение дипломного проекта на форуме (проект не мой): http://www.sql.ru/forum/actualthread.aspx?bid=58&tid=232406&hl=%f0%e5%ef%eb%e8%ea%e0%f6%e8%e8

28.      Дискуссия о репликации на форуме: http://www.sql.ru/forum/actualthread.aspx?bid=36&tid=174801&hl=%f0%e5%ef%eb%e8%ea%e0%f6%e8%ff

29.      Дискуссия о репликации на форуме: http://sql.ru/forum/actualthread.aspx?bid=10&tid=175586&pg=1

30.      Дискуссия о репликации на форуме: http://www.sql.ru/forum/actualthread.aspx?bid=36&tid=37654&hl=%f0%e5%ef%eb%e8%ea%e0%f6%e8%ff

Продукты

31.      Репликатор MobiLink (MySQL) http://www.ianywhere.com/developer/product_manuals/sqlanywhere/0901/en/html/dbmlen9/00000134.htm

32.      Список ссылок по репликации (IB): http://www.ibase.ru/develop.htm#repl

33.      Репликаторы (IB): http://www.ibase.ru/d_repl.htm

34.      Репликатор (Oracle, MS Sql Server, DB2, Daffodil DB, PostgreSql Derby): http://www.daffodildb.com/replicator/heterogeneous_database_replication.html

35.      Open Source репликатор «FireBird Replication Engine»: http://fibre.sourceforge.net/docs/index.html

36.      Репликация на SourceForge http://sourceforge.net/search/?words=replication&type_of_search=soft - SourceForge

37.      Репликатор. DataX http://www.ci.ru/inform18_99/p_07_lum.htm

38.      Репликатор «db4o Replication System (dRS) :: Version 1.0»: http://www.db4o.com/about/productinformation/features/drs.aspx

Другие ссылки

39.      The MIT License: http://www.opensource.org/licenses/mit-license.php

Литература

40.      Литература: К. Дейт. Введение в системы баз данных, 6-е изд. Диалектика, 1998

ПРИЛОЖЕНИЕ. DOWNLOADS

1.                 Исходный код прототипа (215KB) http://repl2.narod.ru/Replicator_1_beta_src_only.zip (для компиляции нужен Delphi 7.0)

2.                 Исходный код прототипа + скомпилированные exe-файлы (1.48MB) http://repl2.narod.ru/Replicator_1_beta.zip

3.                 Документация по БД в html-формате (119KB) http://repl2.narod.ru/Doc_Replicator_1_beta.zip

Хостинг от uCoz