Почему в РИБ 1С не снимается регистрация изменений при одностороннем обмене и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Архитектурные принципы механизма сообщений обмена и квитирования

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

Каждое формируемое сообщение обмена содержит служебный заголовок, в котором фиксируются ключевые атрибуты:

Когда в центральной базе отрабатывает выгрузка, объект ЗаписьСообщенияОбмена создает файл, записывает заголовок с инкрементированным номером сообщения и сериализует зарегистрированные объекты. Однако сама процедура выгрузки не удаляет записи из таблиц регистрации изменений. Платформа не может знать, дойдет ли файл до получателя, не будет ли он поврежден при передаче по сети или отменен транзакцией загрузки. Если бы платформа удаляла регистрацию в момент выгрузки, любой сбой доставки приводил бы к безвозвратной рассинхронизации данных.

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

Диагностика состояния обмена в информационной базе

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

  1. Анализ реквизитов узла плана обмена: откройте форму соответствующего узла плана обмена. Обратите внимание на реквизиты «Номер отправленного» и «Номер принятого». Если номер отправленного непрерывно растет (например, достиг 150), а номер принятого застыл на нуле или начальном значении, подтверждения в базу не поступают.
  2. Использование обработки «Регистрация изменений для обмена данными»: откройте обработку в центральной базе и выберите подчиненный узел. В дереве метаданных будет видно огромное количество зарегистрированных объектов, число которых не уменьшается после завершения сеанса выгрузки.
  3. Анализ размера выгружаемых сообщений: сравните размер последовательно созданных файлов обмена. При отсутствии квитирования размер каждого следующего файла строго больше предыдущего, даже если в информационной базе было изменено всего несколько справочников.

Способ 1. Организация двухстороннего обмена со служебными квитанциями (рекомендуемый)

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

Для реализации этого способа в подчиненной конфигурации (в модуле плана обмена) переопределяется стандартный обработчик событий:


Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента)
    // Полностью подавляем выгрузку любых прикладных данных в центральную базу
    ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
КонецПроцедуры

Механизм работает следующим образом:

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

Ограничения: требуется наличие двустороннего канала связи (сетевой папки, FTP, веб-сервиса или почты) между узлами.

Способ 2. Отключение регистрации изменений в подчиненном узле

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

Для этого в свойствах состава плана обмена для каждого объекта метаданных можно установить свойство Авторегистрация в значение Запретить, либо использовать обработчик модуля плана обмена:


Процедура ПриРегистрацииИзменений(Узел, Отказ)
    // Запрещаем регистрацию любых данных для главного узла
    Если Узел = ПланыОбмена.ГлавныйУзел() Тогда
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

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

Способ 3. Программная очистка регистрации изменений (для изолированных контуров)

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

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

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

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

Пример корректного программного удаления регистрации по номеру сообщения:


// Получаем узел получателя
УзелПриемник = ПланыОбмена.Полный.НайтиПоКоду("LVV");

Если ЗначениеЗаполнено(УзелПриемник) Тогда
    // Получаем номер только что выгруженного сообщения из узла
    НомерВыгруженного = УзелПриемник.НомерОтправленного;
    
    // Снимаем регистрацию только для объектов, попавших в данную посылку
    ПланыОбмена.УдалитьРегистрациюИзменений(УзелПриемник, НомерВыгруженного);
КонецЕсли;

Критические ограничения и риски способа:

Сводные рекомендации по выбору решения

При проектировании однонаправленных обменов на базе РИБ следует придерживаться четких правил:

← На главную