При работе с распределенными информационными базами (РИБ) разработчики нередко задаются вопросом: как поведет себя механизм обмена данными, если в двух независимых периферийных узлах появятся объекты одного типа с абсолютно одинаковыми уникальными идентификаторами (GUID)? Разберем детально механику работы платформы «1С:Предприятие», сценарии перезаписи данных, вероятность случайного дублирования и реальные причины возникновения подобных коллизий на практике.
Поведение платформы при синхронизации объектов с одинаковым GUID
Для платформы «1С:Предприятие» уникальный идентификатор ссылки является главным признаком существования объекта в базе. Если два разных периферийных узла отправляют в центральную базу данные с одинаковым типом и одинаковым УникальныйИдентификатор, система воспринимает их как один и тот же объект.
Рассмотрим по шагам, как развивается процесс обмена:
Загрузка первого пакета: Документ или элемент справочника из первого периферийного узла успешно записывается в центральную базу с присвоенным GUID.
Загрузка второго пакета: При поступлении сообщения обмена из второго периферийного узла платформа находит в таблице существующую запись по переданному GUID и выполняет ее обновление (перезапись). В результате данные первого документа полностью заменяются реквизитами и табличными частями второго документа.
Дальнейшая миграция по узлам: По правилам миграции РИБ измененный в центральной базе объект регистрируется к отправке во все узлы. Когда пакет дойдет до первого узла, исходный созданный там документ также будет перезаписан версией из второго узла.
Таким образом, по умолчанию действует принцип «побеждает последний пришедший пакет» (Last Write Wins). Один объект полностью сотрет другой без выдачи платформенных ошибок нарушения уникальности данных.
Как генерируется GUID в 1С и какова вероятность случайной коллизии
Проанализируем алгоритм создания идентификаторов ссылок. Платформа 1С использует стандарт генерации идентификаторов на основе версии 1 (UUID Version 1 / time-based):
В структуру 128-битного значения закладываются точная временная метка (таймстемп), счетчик последовательности и идентификатор узла (на основе MAC-адреса сетевого интерфейса сервера 1С или клиентского ПК).
Для оптимизации работы СУБД платформа переставляет байты в представлении идентификатора, чтобы новые ссылки последовательно возрастали. Это исключает сильную фрагментацию страниц индексов в таблицах СУБД.
Каждый объект метаданных хранится в изолированной таблице СУБД. Если совпадут GUID у объектов разных типов (например, у документа «Реализация товаров» и справочника «Контрагенты»), конфликта не произойдет — платформа корректно сопоставляет сущности сначала по типу метаданных, а затем по UUID.
Математическая вероятность того, что два разных физических сервера или клиентских сеанса случайно сгенерируют полностью идентичный UUIDv1 для одного типа объекта, практически равна нулю.
Реальные причины возникновения одинаковых GUID
Несмотря на ничтожную вероятность случайного совпадения, на практике разработчики и администраторы регулярно сталкиваются с коллизиями идентификаторов. Выясним основные причины:
Программная установка ссылок: Разработчик может явно задать одинаковый идентификатор новому объекту до момента его записи.
Клонирование виртуальных машин: Если серверы приложений или базы были развернуты из одного снапшота виртуальной машины с сохранением одинаковых MAC-адресов и принудительно синхронизированным временем, генератор UUIDv1 на разных узлах может выдать дубли.
Разделение и последующее сведение баз: Когда рабочую базу копируют для нескольких филиалов, данные в них продолжают жить изолированно (редактируются названия, реквизиты элементов справочников), а затем эти базы пытаются объединить через планы обмена по ссылкам. В таком случае одинаковые исторические GUID перезатирают разные актуальные данные.
Посмотрим на пример кода, который приводит к искусственному созданию одинаковых ссылок в разных узлах:
// Принудительное назначение предопределенного идентификатора новому объекту
Идентификатор = Новый УникальныйИдентификатор("47c1392f-67ba-4557-9e91-52cd36fbcdce");
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(Идентификатор);
ЭлементСправочника = Справочники.Контрагенты.СоздатьЭлемент();
ЭлементСправочника.УстановитьСсылкуНового(НоваяСсылка);
ЭлементСправочника.Наименование = "Контрагент из узла А";
ЭлементСправочника.Записать();
Если выполнить аналогичный код в узле «Б» с другим наименованием, после прохождения циклов обмена один из контрагентов будет безвозвратно затерт другим.
Как предотвратить потерю данных и разрешать конфликты
Для предотвращения перезаписи критически важных данных и разрешения коллизий в распределенных системах используются следующие подходы:
Обработчики событий планов обмена: В модуле плана обмена можно использовать предопределенные события ПриПолученииДанныхОтГлавного и ПриПолученииДанныхОтПодчиненного. В этих обработчиках можно программно сравнить реквизиты входящего объекта с текущей версией в базе (например, дату модификации или номер версии) и при необходимости отменить стандартную перезапись.
Механизмы разрешения коллизий БСП: Библиотека стандартных подсистем предоставляет подсистему версионирования и настройки приоритетов узлов. При возникновении конфликтов система регистрирует спорную ситуацию в специальном регистре для ручного разбора администратором.
Программная замена ссылок: Если коллизия уже произошла, для разделения слившихся объектов создают новый элемент с корректным GUID и выполняют глобальную перепривязку связей с помощью метода ЗаменитьСсылки().