Задача - одновремменное редактирование документа несколькими пользователями
**Существует множество способов конвергентного разрешения конфликтов.
**
* Присвоить каждой операции записи уникальный идентификатор (например, метку даты/времени, случайное длинное число, UUID или хеш ключа и значения), после чего просто выбрать операцию («победителя») с максимальным значением этого идентификатора, а остальные отбросить. В случае использования метки даты/времени в качестве идентификатора этот метод известен под названием «выигрывает последний» (last write wins, LWW). Хотя этот подход очень популярен, ему свойственно терять данные. Мы обсудим LWW подробнее в конце этой главы (в подразделе «Обнаружение конкурентных операций записи» раздела 5.4).
* Присвоить уникальный идентификатор каждой реплике и считать, что у исходящих от реплик с большим номером операций записи есть приоритет перед теми, которые исходят от реплик с меньшим. Этот подход также приводит к потерям данных.
* Каким-либо образом слить значения воедино, например, выстроить их в алфавитном порядке, после чего выполнить их конкатенацию.
* Заносить конфликты в заданную в явном виде структуру данных для хранения и написать код приложения, который бы разрешал конфликты позднее (возможно, спрашивая для этого пользователя).
**Пользовательская логика разрешения конфликтов**
Поскольку то, как лучше всего разрешить конфликт, зависит от приложения, большинство программных средств репликации с несколькими ведущими узлами позволяют создать логику разрешения конфликтов в коде приложения. Этот код может выполняться при записи или чтении.
* При записи. При обнаружении конфликта в журнале реплицированных изменений СУБД вызывает обработчик конфликтов. Например, Bucardo позволяет писать с этой целью сниппеты на языке программирования Perl. Подобный обработчик обычно не может спросить что-либо у пользователя — он запускается в фоновом процессе и должен выполняться быстро.
* При чтении. При обнаружении конфликта система сохраняет информацию обо всех конфликтующих операциях записи. При следующей операции чтения все эти различные версии данных возвращаются приложению. Далее оно может спросить пользователя или разрешить конфликт автоматически, после чего записать результаты обратно в БД. Подобным образом работает, например, CouchDB.
Обратите внимание: подобное разрешение конфликтов выполняется обычно на уровне отдельных строк или документов, а не транзакций в целом. Следовательно, в случае транзакции, выполняющей атомарно несколько различных операций записи, каждая операция рассматривается отдельно для целей разрешения конфликтов.
**Автоматическое разрешение конфликтов**
Правила разрешения конфликтов быстро усложняются, и пользовательский код становится подвержен ошибкам. В качестве примера неожиданных эффектов вследствие разрешения конфликтов часто упоминается Amazon: логика разрешения конфликтов корзины заказов сохраняет в течение некоторого времени добавленные в корзину товары, но не удаляемые из нее. Следовательно, покупатели иногда видят повторное появление в корзине заказов ранее удаленных из нее товаров.
Существуют интересные исследования на тему автоматического разрешения конфликтов, вызванных конкурентными изменениями данных. Кое-что из них достойно упоминания.
* Бесконфликтные реплицируемые типы данных (conflict-free replicated datatype, CRDT) — семейство структур данных для множеств, ассоциативных словарей, упорядоченных списков, счетчиков и др., допускающие конкурентное редактирование несколькими пользователями и автоматически разрешающие конфликты разумным образом. Некоторые из CRDT были реализованы в Riak 2.0.
* Объединяемые хранимые структуры данных (mergeable persistent data structures) обеспечивают отслеживание истории явным образом аналогично системе контроля версий Git и используют трехстороннюю функцию слияния (в отличие от двухстороннего слияния в CRDT).
* Операциональное преобразование (operational transformation) представляет собой алгоритм разрешения конфликтов, используемый в таких приложениях для совместного редактирования, как Etherpad и Google Docs. Он был спроектирован специально для совместного редактирования упорядоченного списка элементов, например перечня букв, составляющего текстовый документ.
Автоматическое разрешение конфликтов значительно упрощает для приложений применение синхронизации данных с несколькими ведущими узлами. Реализации этих алгоритмов в БД все еще довольно незрелы, но есть вероятность, что в будущем они будут включаться во все большее количество реплицируемых информационных систем.