Как решить проблему медленной синхронизации данных при переносе сверхкрупных документов из БП Агрокомплекс в Управление холдингом?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет Промышленность, строительство и АПК
← На главную

При автоматизации крупных агропромышленных холдингов технические специалисты часто сталкиваются со спецификой сельскохозяйственного учета. Одной из наиболее сложных задач является закрытие года. В растениеводстве и животноводстве производственный цикл носит затяжной характер, из-за чего в течение всего календарного года затраты аккумулируются на счетах косвенных расходов (25 и 26), а в декабре происходит их глобальное распределение на затраты основного производства (счет 20).

В результате этой операции в информационной базе 1С:Бухгалтерия предприятия Агрокомплекс (БП) формируются «мега-документы» закрытия месяца, содержащие сотни тысяч бухгалтерских проводок (вплоть до 400 000 и более в одном документе). Попытка передать такой документ через стандартный механизм синхронизации данных (например, на базе формата EnterpriseData) в центральную базу 1С:Управление холдингом (УХ) приводит к полной остановке обмена, зависанию рабочих процессов и блокировке передачи другой оперативной информации на недели или даже месяцы.

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

Почему стандартный обмен зависает на сверхкрупных документах?

Прежде чем переходить к решениям, выясним первопричину сбоя на техническом уровне кластера 1С и СУБД:

  1. Крах по памяти (Memory Limit): Стандартные правила обмена используют XML/JSON-сериализацию через XDTO. При выгрузке документа с 400 000 строк объект целиком помещается в оперативную память для построения дерева XML. Это вызывает лавинообразный рост потребления RAM рабочим процессом платформы rphost. Процесс либо принудительно перезапускается операционной системой по превышению лимитов, либо уходит в бесконечный своп (swap).
  2. Таймауты веб-сервисов: Если обмен настроен через HTTP или Web-сервисы, время ожидания ответа обычно ограничено (по умолчанию 60–120 секунд). Чтение, разбор и запись сотен тысяч проводок физически не могут уложиться в этот интервал, из-за чего соединение разрывается по таймауту.
  3. Монопольные блокировки СУБД: Запись и проведение огромного документа в базе-приемнике происходит в рамках одной транзакции. СУБД накладывает долгосрочные блокировки на таблицы регистра бухгалтерии Хозрасчетный, парализуя работу остальных пользователей и блокируя другие сессии обмена.

Рассмотрим пошагово методы борьбы с этой проблемой — от простых организационных мер до глубокой переработки архитектуры интеграции.

Решение 1. Интеллектуальная свертка (группировка) проводок перед отправкой

Проанализируем методологическую необходимость передачи детальных данных. Центральной базе 1С:Управление холдингом, которая используется для консолидации и управленческой отчетности, чаще всего не требуется субконто-детализация первичных затрат каждого отдельного поля или единицы техники. Ей важен итоговый финансовый результат.

Для минимизации объема данных мы можем написать алгоритм свертки проводок на стороне источника (БП) перед отправкой. Вместо 400 000 детальных записей мы сгруппируем их по ключевым разрезам аналитики (Счет Дт/Кт, Субконто, Подразделение) и просуммируем.

Посмотрим на пример запроса, который позволяет выполнить группировку движений мега-документа перед отправкой в приемник:


// Пример запроса для свертки проводок перед выгрузкой
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	ХозрасчетныйДвижения.СчетДт КАК СчетДт,
|	ХозрасчетныйДвижения.СчетКт КАК СчетКт,
|	ХозрасчетныйДвижения.СубконтоДт1 КАК СубконтоДт1,
|	ХозрасчетныйДвижения.СубконтоКт1 КАК СубконтоКт1,
|	ХозрасчетныйДвижения.ПодразделениеДт КАК ПодразделениеДт,
|	ХозрасчетныйДвижения.ПодразделениеКт КАК ПодразделениеКт,
|	СУММА(ХозрасчетныйДвижения.Сумма) КАК Сумма
|ИЗ
|	РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(&НачалоПериода, &КонецПериода, Регистратор = &Документ) КАК ХозрасчетныйДвижения
|
|СГРУППИРОВАТЬ ПО
|	ХозрасчетныйДвижения.СчетДт,
|	ХозрасчетныйДвижения.СчетКт,
|	ХозрасчетныйДвижения.СубконтоДт1,
|	ХозрасчетныйДвижения.СубконтоКт1,
|	ХозрасчетныйДвижения.ПодразделениеДт,
|	ХозрасчетныйДвижения.ПодразделениеКт";

Запрос.УстановитьПараметр("Документ", СсылкаНаМегаДокумент);
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(СсылкаНаМегаДокумент.Дата));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(СсылкаНаМегаДокумент.Дата));

РезультатЗапроса = Запрос.Выполнить().Выгрузить();

Использование этого метода позволяет сократить объем выгружаемых проводок на 95–98% без потери методологической точности в базе-приемнике. Вместо сотен тысяч строк мы передаем компактную таблицу из 2 000–5 000 записей, которая обрабатывается стандартным механизмом за секунды.

Решение 2. Физическое дробление документа на порции в источнике

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

Разберем по шагам логику реализации этого механизма:

  1. Создаем специальную обработку, которая запускается перед началом синхронизации данных.
  2. Обработка находит тяжелые документы распределения затрат и копирует их структуру, разбивая табличные части проводок на порции (например, по 10 000 строк в каждой).
  3. Каждая порция записывается как отдельный служебный документ.
  4. Вместо одного исходного мега-документа к обмену регистрируются 40 небольших документов.

Рассмотрим пример кода на встроенном языке 1С, реализующий логику порционного создания документов:


// Алгоритм разбиения таблицы проводок мега-документа на порции
РазмерПорции = 10000;
ВсегоСтрок = ТаблицаПроводок.Количество();
НомерПорции = 1;

Пока (НомерПорции - 1) * РазмерПорции < ВсегоСтрок Цикл
    НовыйДокумент = Документы.ОперацияБух.СоздатьДокумент();
    НовыйДокумент.Дата = ИсходныйДокумент.Дата;
    НовыйДокумент.Организация = ИсходныйДокумент.Организация;
    НовыйДокумент.Содержание = "Порция №" + Строка(НомерПорции) + " распределения затрат за год";
    
    // Заполняем движения по регистру Хозрасчетный для текущей порции
    НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
    ДвиженияХозрасчетный = НовыйДокумент.Движения.Хозрасчетный;
    
    НачальныйИндекс = (НомерПорции - 1) * РазмерПорции;
    КонечныйИндекс = Мин(НомерПорции * РазмерПорции - 1, ВсегоСтрок - 1);
    
    Для Индекс = НачальныйИндекс По КонечныйИндекс Цикл
        СтрокаИсточника = ТаблицаПроводок[Индекс];
        НоваяПроводка = ДвиженияХозрасчетный.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяПроводка, СтрокаИсточника);
        НоваяПроводка.Период = ИсходныйДокумент.Дата;
        НоваяПроводка.Организация = ИсходныйДокумент.Организация;
    КонецЦикла;
    
    ДвиженияХозрасчетный.Записать();
    НомерПорции = НомерПорции + 1;
КонецЦикла;

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

Решение 3. Разделение каналов синхронизации (НСИ и транзакции отдельно)

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

Для исправления ситуации настроим два независимых канала обмена:

Решение 4. Асинхронная загрузка через регистр входящих сообщений

Если мы хотим полностью разгрузить сессию синхронизации, применим архитектурный паттерн «Регистр входящих сообщений»:

  1. При выгрузке из БП тяжелый документ упаковывается в плоский файл обмена (XML/JSON) и передается «как есть» без попытки его обработки и проведения на стороне приемника.
  2. В базе-приемнике (УХ) создается запись в специальном регистре сведений, например, РегистрСведений.ВходящийБуферОбмена, где в реквизите с типом ХранилищеЗначения сохраняется переданный текст файла. Сессия обмена мгновенно закрывается, не дожидаясь разбора данных.
  3. В фоне на стороне УХ работает регламентное задание. Оно считывает XML-строку из буфера, порциями парсит его и создает транзакции записи в базу данных. Вся тяжелая работа переносится во внерабочее время.

Решение 5. Переход на низкоуровневое потоковое чтение (StAX)

Когда стандартный механизм EnterpriseData падает из-за нехватки памяти, рекомендуется отказаться от объектной выгрузки через XDTO. Вместо этого разработаем собственный HTTP-сервис, использующий низкоуровневые объекты платформы 1С:

Системные настройки СУБД и кластера 1С

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

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

← На главную