При работе с Распределенными Информационными Базами (РИБ) в конфигурации 1С:Розница 2.3 системные администраторы и программисты часто сталкиваются с ситуацией, когда после аварийного завершения обновления или пересоздания периферийного узла центральная база начинает бесконечно выгружать файлы обмена гигантского размера (вплоть до нескольких гигабайт). При этом сам обмен формально проходит без видимых ошибок: данные из периферийной базы успешно загружаются в центр, но при каждой последующей синхронизации центральный узел снова и снова формирует один и тот же огромный пакет данных. Для контроля состояния синхронизации по всем точкам сети можно использовать инструмент мониторинга обменов с магазинами в РИБ.
В этой статье мы подробно разберем, как устроен механизм подтверждения доставки сообщений в РИБ 1С, выясним технические причины возникновения этой проблемы и рассмотрим пошаговые сценарии ее решения.
Для того чтобы понять природу бесконечной выгрузки, проанализируем базовый транзакционный механизм, который платформа 1С использует для минимизации передаваемого трафика. Этот механизм называется квитированием (или подтверждением доставки) и работает по строгому замкнутому циклу:
ConfirmationMessageNo со значением 150.Если этот цикл разрывается на любом из этапов, центральный узел считает, что периферийная база так и не получила изменения №150. Соответственно, при следующем сеансе связи центральная база обязана повторно выгрузить все эти данные, что и приводит к зацикливанию выгрузки файла размером в 4 ГБ.
Рассмотрим ситуацию, с которой столкнулся автор темы. Из-за сбоя обновления периферийная база была удалена в центральном узле и создана заново. При создании нового узла "с нуля" внутренние счетчики сообщений обнулились.
Если центральная база ожидает от периферийной подтверждения пакета №150, а вновь созданная периферийная база шлет в заголовке сообщения номер подтверждения 0 (так как для нее это первый обмен), центральная база игнорирует это подтверждение. Регистрация изменений в центре не очищается, и все накопленные за годы работы данные продолжают выгружаться при каждой итерации.
Для решения этой проблемы нам необходимо принудительно синхронизировать номера сообщений в обеих базах. Выполним это по шагам:
Номер отправленного = X, Номер принятого = Y.Номер отправленного = Y, Номер принятого = X.Если интерактивно изменить номера не получается или база работает в режиме, ограничивающем доступ к этим реквизитам, мы можем воспользоваться программным кодом. Запустим внешнюю обработку или воспользуемся групповой обработкой объектов, выполнив следующий код на стороне центральной базы:
// Корректировка номеров сообщений узла обмена программно
УзелОбъект = СсылкаНаУзелРИБ.ПолучитьОбъект();
УзелОбъект.НомерОтправленного = 1; // Устанавливаем начальное значение
УзелОбъект.НомерПринятого = 1;
УзелОбъект.Записать();
После этого аналогичные действия (со значениями 1 и 1) необходимо проделать на стороне периферийной базы, чтобы полностью синхронизировать отправку и прием с чистого листа.
Когда обмен настроен через файловый каталог, синхронизируемый сторонним облачным клиентом (например, Google Диск), критическим фактором становится время загрузки тяжелых файлов в облако.
Проанализируем стандартный сценарий возникновения ошибки при объеме данных 4 ГБ:
Для проверки этой гипотезы временно исключим влияние облачного хранилища. Настроим синхронизацию через локальный каталог на жестком диске или физический USB-накопитель. Выполним полный цикл обмена вручную, перенося файлы на флешке. Если размер выгружаемого файла из центра резко снизится с 4 ГБ до нескольких килобайт/мегабайт, значит, проблема заключалась исключительно в сетевых задержках облачного клиента.
Чтение и запись XML-файла размером 4 ГБ — это ресурсоемкая операция, требующая значительного объема оперативной памяти. Если на сервере или локальном компьютере установлена 32-разрядная версия платформы 1С:Предприятие, процесс 1cv8.exe физически не может адресовать более 2-4 ГБ оперативной памяти.
В процессе загрузки такого тяжелого пакета транзакция может аварийно завершиться на стороне СУБД или файловой системы из-за ошибки "Out of memory". При этом некоторые прикладные объекты (например, документы поступлений или чеки) могут физически успеть записаться в базу данных до падения системы, что создает у пользователя ложную иллюзию успешного обмена. Однако финальная транзакция записи номера принятого сообщения в плане обмена откатывается назад. Как результат — при следующем сеансе связи центральная база вновь инициирует выгрузку всего объема данных.
Если после неудачного обновления до последней версии в центральной базе остались незавершенные фоновые задания отложенного обновления данных (которые можно отследить через обработку РезультатыОбновленияПрограммы), программа будет постоянно находиться в режиме модификации данных.
Служебные алгоритмы конфигурации 1С:Розница в фоновом режиме перезаписывают старые документы и регистры сведений (например, ИнформативныеОстаткиПоМагазинам или данные штрихкодов), что лавинообразно регистрирует их к отправке в РИБ. В таком случае файл обмена будет весить 4 ГБ не из-за ошибки квитирования, а из-за того, что система действительно пытается отправить измененные фоновым обновлением объекты.
Рассмотрим, как отключить авторегистрацию и очистить накопленные изменения программным методом, если базы данных фактически уже идентичны по своему наполнению.
Если мы убедились, что все справочники, документы и остатки в центральной и периферийной базах полностью совпадают, а бесконечный цикл выгрузки файла 4 ГБ продолжается, наиболее эффективным решением будет принудительное обнуление регистрации изменений в центральном узле. Для выборочного или полного снятия объектов с регистрации без написания кода подойдёт обработка для отмены регистрации документов в плане обмена.
Для этого воспользуемся стандартным или программным методом очистки:
Если объем зарегистрированных данных настолько велик, что стандартная интерактивная форма зависает или аварийно закрывается по нехватке памяти, выполним очистку с помощью следующего программного кода в контексте внешней обработки:
// Программная очистка регистрации изменений для выбранного узла
УзелОбмена = ПланыОбмена.ПоставитьИмяПланаОбмена.НайтиПоКоду("КодПериферийногоУзла");
Если ЗначениеЗаполнено(УзелОбмена) Тогда
// Удаляем регистрацию абсолютно всех объектов для данного узла
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена);
Сообщить("Регистрация изменений успешно очищена для узла: " + УзелОбмена);
Иначе
Сообщить("Указанный узел обмена не найден!");
КонецЕсли;
Применение этого метода мгновенно остановит бесконечную выгрузку. При последующих продажах и создании новых документов в периферийной или центральной базе регистрация изменений начнется с чистого листа, а файлы обмена вернутся к своим нормальным рабочим размерам в несколько мегабайт.