При организации автоматического обмена данными между конфигурациями 1С:Предприятие с использованием XML-файлов большого объема разработчики часто сталкиваются со специфическими и труднодиагностируемыми сбоями. Особенно остро эти проблемы проявляются при выполнении обмена в контексте фоновых заданий на стороне сервера. В нашей практике мы разберем две взаимосвязанные и крайне коварные ошибки, которые могут парализовать процесс синхронизации данных.
Первая ошибка возникает на уровне СУБД Microsoft SQL Server: "Attempting to grow LOB beyond maximum allowed size of 2147483647 bytes" (Код ошибки SQL Server: 7119). Вторая ошибка возвращается встроенным XML-парсером платформы 1С: "Extra content at the end of the document" (Фатальная ошибка, позиция [1,1]). Мы подробно проанализируем физические причины возникновения этих сбоев и выработаем надежные архитектурные решения для их устранения.
Для начала давайте разберемся, что представляет собой аббревиатура LOB в контексте СУБД MS SQL Server. Под LOB (Large Object) понимаются специализированные типы данных большого объема, такие как NVARCHAR(MAX), VARCHAR(MAX), VARBINARY(MAX), а также устаревшие типы TEXT, NTEXT и IMAGE. На уровне движка базы данных для хранения таких объектов выделяются отдельные страницы памяти вне основной таблицы.
СУБД Microsoft SQL Server накладывает жесткое физическое ограничение на максимальный размер любого одиночного значения этих типов — он не может превышать $2^{31} - 1$ байт, что составляет ровно 2 147 483 647 байт (2 ГБ). Если СУБД в процессе выполнения транзакции пытается записать в одну ячейку таблицы, передать в качестве одного параметра или обработать во временной таблице tempdb непрерывный массив данных, превышающий этот лимит, она аварийно завершает операцию с ошибкой 7119.
Выясним, почему это происходит при загрузке XML в 1С, ведь исходный размер файла на диске может быть существенно меньше 2 ГБ (например, около 1 ГБ):
УниверсальныйОбменДаннымиXML) пытаются прочитать тяжелый файл обмена и зафиксировать все изменения в СУБД в рамках одной транзакции. При этом сервер 1С формирует огромные SQL-запросы, которые переполняют буфер транзакций и временные таблицы СУБД.Рассмотрим основные архитектурные подходы, которые позволят нам обойти ограничение СУБД в 2 ГБ.
Способ 1. Исключение двоичных данных из XML-структуры. Передача "тяжелых" бинарных файлов (картинки, документы) непосредственно внутри тела XML-документа является грубой архитектурной ошибкой. Вместо этого мы должны сохранять двоичные данные во внешнем хранилище (например, в сетевой папке, на FTP-сервере или в облачном объектном S3-хранилище). В самом XML-файле мы передаем только метаданные и относительную ссылку или уникальный идентификатор файла. При загрузке на стороне приемника сервер 1С должен программно скачивать файлы по ссылкам поочередно, исключая перегрузку памяти.
Способ 2. Пакетная выгрузка данных (Chunking). Если XML-файл разрастается до огромных размеров из-за колоссального количества выгружаемых документов или справочников, его необходимо дробить на пакеты еще на этапе генерации в источнике. Оптимальный размер одного пакета составляет от 50 до 100 МБ. Это гарантирует стабильную обработку файлов без критической нагрузки на оперативную память сервера приложений 1С и СУБД.
Способ 3. Порционное коммитирование транзакций. Нам необходимо отказаться от фиксации всей загрузки в рамках одной неделимой транзакции базы данных. Мы должны осуществлять запись порциями — например, каждые 500 или 1000 объектов. Для этого в кодовой базе обработчика обмена следует предусмотреть периодический вызов методов ЗафиксироватьТранзакцию() и НачатьТранзакцию().
Теперь проанализируем вторую проблему, когда при загрузке файла через фоновое задание мы внезапно получаем фатальную ошибку разбора XML: "Extra content at the end of the document. Line 1, Position 1". Интересно, что при попытке открыть этот же файл в текстовом редакторе или браузере он выглядит абсолютно корректным, а при загрузке вручную на клиенте через интерактивную форму все отрабатывает без сбоев.
Разберем детально физические причины этого парадокса:
EF BB BF) в самом начале текстового файла, предназначенную для определения порядка байтов в потоке.
rphost (особенно если сервер функционирует под ОС Linux или запущен под системной учетной записью usr1cv8 с нестандартными региональными настройками) задействует кроссплатформенный парсер (на базе библиотеки libxml2). Если локаль сервера настроена некорректно, парсер может воспринять BOM-байты как недопустимые символы (мусор) прямо перед объявлением XML-документа <?xml...>, либо неверно рассчитать длину считываемого потока. Это приводит к немедленному сбою с вердиктом "Extra content...".\\srv-s1cm1\ERP_SYNC\..., то ошибка разбора исчезает! Это классический признак кэширования сетевых папок ОС Windows. При циклической перезаписи файла обмена с фиксированным именем сетевые механизмы кэширования могут отдавать серверному процессу 1С устаревшую, частично заблокированную или недописанную версию файла. В результате парсер считывает поврежденный поток данных, доходит до непредвиденного конца файла или натыкается на блокировки чтения и выдает фатальную ошибку структуры.Для предотвращения подобных ошибок при проектировании обменов на сервере необходимо строго следовать двум правилам.
Правило 1. Запись XML-файлов строго без BOM. При формировании файлов обмена в системе-источнике мы должны принудительно отключать запись сигнатуры BOM. В платформе 1С это реализуется с помощью правильной инициализации объекта ЗаписьТекста, где пятый параметр конструктора отвечает за вывод BOM-символов.
Проанализируем пример кода, гарантирующий создание файла UTF-8 без BOM:
// Правильная выгрузка XML без использования BOM
ПутьКФайлу = "\\srv-s1cm1\ERP_SYNC\UPP_ERPPM\MessageUPP_ERP.xml";
// Пятый параметр "Ложь" отключает запись BOM-символов
ТекстовыйФайл = Новый ЗаписьТекста(ПутьКФайлу, КодировкаТекста.UTF8, , , Ложь);
ЗаписьXMLДанных = Новый ЗаписьXML();
ЗаписьXMLДанных.ОткрытьФайл(ТекстовыйФайл);
// Производим запись структуры XML документа...
ЗаписьXMLДанных.ЗаписатьОбъявлениеXML();
// ... логика выгрузки объектов ...
ЗаписьXMLДанных.Закрыть();
ТекстовыйФайл.Закрыть();
Правило 2. Локальное чтение файлов на сервере 1С. Крайне не рекомендуется осуществлять чтение "тяжелых" XML-файлов напрямую по сетевым путям (таким как \\server\folder\file.xml) в методах серверного разбора. Сетевые задержки, микросбои сетевых адаптеров и механизмы блокировок файлов в многопоточной среде гарантированно будут приводить к сбоям парсинга.
Правильный алгоритм работы с сетевыми ресурсами на сервере должен выглядеть так:
КопироватьФайл()).Давайте посмотрим на реализацию этого отказоустойчивого алгоритма загрузки:
&НаСервере
Процедура ВыполнитьЧтениеФайлаОбменаНаСервере(Знач СетевойПутьКФайлу)
// Генерируем уникальное имя для предотвращения кэширования SMB
УникальныйИдентификаторФайла = Строка(Новый УникальныйИдентификатор);
ЛокальныйПуть = КаталогВременныхФайлов() + УникальныйИдентификаторФайла + ".xml";
// Копируем сетевой файл на локальный диск сервера 1С
Попытка
КопироватьФайл(СетевойПутьКФайлу, ЛокальныйПуть);
Исключение
ЗаписьЖурналаРегистрации("СинхронизацияДанных", УровеньЖурналаРегистрации.Ошибка,,,
"Не удалось скопировать файл во временное хранилище сервера. Описание: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
ФайлОбмена = Новый ЧтениеXML();
Попытка
ФайлОбмена.ОткрытьФайл(ЛокальныйПуть);
// Запускаем последовательное чтение файла
Пока ФайлОбмена.Прочитать() Цикл
// Здесь реализуется логика обработки узлов XML
// Например, анализ элементов и запись в СУБД порциями
КонецЦикла;
ФайлОбмена.Закрыть();
Исключение
// Обязательно закрываем файл в случае ошибки, чтобы снять блокировку
ФайлОбмена.Закрыть();
// Удаляем временный файл перед генерацией исключения
УдалитьФайлы(ЛокальныйПуть);
ВызватьИсключение "Ошибка парсинга XML на сервере: " + ОписаниеОшибки();
КонецПопытки;
// Удаляем временную копию после успешной обработки
Попытка
УдалитьФайлы(ЛокальныйПуть);
Исключение
// Логируем ошибку удаления, но не прерываем работу
ЗаписьЖурналаРегистрации("СинхронизацияДанных", УровеньЖурналаРегистрации.Предупреждение,,,
"Не удалось удалить временный локальный файл: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Применение данной методики позволяет полностью исключить влияние сетевых протоколов Windows/Samba на процесс парсинга данных, сводит к нулю вероятность возникновения ошибки "Extra content" из-за кэширования сетевых дескрипторов, а также изолирует разбор кодировки от специфических региональных настроек сетевых папок.
Подводя итог, мы видим, что успешная обработка больших объемов XML-данных в 1С требует комплексного подхода: оптимизации хранения двоичных файлов отдельно от текстового XML-пакета, отключения BOM-сигнатур при записи, порционного коммитирования транзакций в СУБД для обхода лимита LOB-объектов в 2 ГБ и обязательного локального кэшивания файлов на сервере приложений 1С для предотвращения сбоев сетевого ввода-вывода.