При интеграции 1С с интернет-магазинами (например, на движке Shop-Script/Webasyst, Bitrix или OpenCart) одной из наиболее частых проблем является аварийное завершение работы системы при передаче больших объемов данных. Ситуация усугубляется, если выгружается не просто текстовый каталог (номенклатура, цены, остатки), а тяжелые медиафайлы — изображения товаров. База данных объемом в несколько гигабайт и каталог на десятки тысяч позиций с картинками могут легко переполнить оперативную память сервера 1С, вызывая ошибку "Недостаточно памяти" или аварийно завершая рабочий процесс rphost.exe.
В этой статье мы подробно разберем, как определить точный размер передаваемого POST-запроса (архива с данными), почему стандартное разбиение на порции в настройках обмена часто не помогает решить проблему с памятью, и какие системные и программные шаги необходимо предпринять для стабильной работы выгрузки.
Если нам необходимо узнать точный размер сформированного пакета непосредственно «в полете», то есть при его отправке на веб-сервер сайта, использование специализированных локальных прокси-серверов является лучшим решением. Рассмотрим этот процесс по шагам на примере программы Fiddler:
Tools -> Options -> HTTPS) обязательно включим опцию "Decrypt HTTPS traffic" и установим корневой сертификат безопасности Fiddler в систему, иначе программа не сможет расшифровать тело запроса.Content-Length. Значение напротив этого параметра указывает точный размер передаваемого POST-запроса (и, соответственно, упакованного zip-архива) в байтах. Разделив это число на 1024 последовательно два раза, мы получим точный вес файла в мегабайтах.Если у нас есть доступ к конфигуратору 1С и коду обработки обмена, мы можем узнать размер отправляемого архива программно, записав данные в Журнал регистрации. Для этого найдем место в коде, где инициализируется отправка HTTP-соединения и создается временный zip-файл на диске (обычно с помощью объекта ЗаписьZipФайла).
Давайте посмотрим на практический пример кода, который определяет размер временного файла перед отправкой:
// ПутьКФайлуАрхива - это переменная, содержащая путь к сформированному ZIP-файлу на диске
ВыгружаемыйФайл = Новый Файл(ПутьКФайлуАрхива);
Если ВыгружаемыйФайл.Существует() Тогда
РазмерВБайтах = ВыгружаемыйФайл.Размер();
РазмерВМегабайтах = Окр(РазмерВБайтах / 1024 / 1024, 2);
// Записываем информацию в Журнал регистрации для последующего анализа
ЗаписьЖурналаРегистрации(
"Интеграция.ОбменССайтом",
УровеньЖурналаРегистрации.Информация,
,
,
"Подготовлен пакет обмена. Имя файла: " + ВыгружаемыйФайл.Имя +
". Размер: " + РазмерВМегабайтах + " МБ."
);
КонецЕсли;
Если же данные не записываются во временный файл на диске, а формируются непосредственно в оперативной памяти в виде двоичных данных, мы можем использовать встроенный метод Размер() объекта ДвоичныеДанные:
// ДвоичныеДанныеАрхива - объект, содержащий упакованный архив в памяти
РазмерВБайтах = ДвоичныеДанныеАрхива.Размер();
РазмерВМегабайтах = Окр(РазмерВБайтах / 1024 / 1024, 2);
Сообщить("Размер отправляемого буфера: " + РазмерВМегабайтах + " МБ.");
Часто пользователи сталкиваются со странным поведением системы: даже при ограничении размера порции (например, выгружать по 5–10 товаров за один раз) сервер 1С все равно потребляет до 99% оперативной памяти и падает. Выясним причину этой проблемы.
Дело в том, что настройка «размер порции» в стандартных модулях обмена чаще всего влияет только на физическую отправку пакетов на сайт, но не на процесс подготовки данных в самой 1С. Перед тем как начать деление товаров на порции, обработка обмена может выполнять один глобальный запрос к базе данных, пытаясь получить всю информацию о номенклатуре и связанных картинках.
Изображения в 1С хранятся в виде двоичных данных (тип ХранилищеЗначений) прямо внутри таблиц базы данных. При выполнении неоптимизированного запроса сервер 1С (процесс rphost.exe) пытается прочитать и удержать в оперативной памяти бинарные файлы тысяч картинок одновременно. В процессе сериализации (подготовки картинок к отправке, перевода их в формат Base64 или сжатия в zip) данные дублируются в памяти несколько раз. В результате 8 ГБ оперативной памяти сервера мгновенно исчерпываются, даже если на сайт в данный момент передается пачка всего из 5 товаров.
Это важнейший шаг, без выполнения которого любые оптимизации кода могут оказаться бесполезными. Проанализируем разницу между разрядностями платформ:
1cv8c.exe или рабочий процесс сервера rphost.exe) физически не может адресовать более 2 ГБ (в редких случаях при настройке ОС — до 3–4 ГБ) оперативной памяти. Как только объем обрабатываемых картинок превышает этот порог, процесс завершается аварийно, вне зависимости от того, сколько физической памяти (хоть 64 ГБ) установлено на сервере.Рекомендация: Установите 64-битный сервер приложений 1С и используйте 64-битный клиент для выполнения «тяжелых» процедур обмена.
Хранение картинок внутри тела самой базы данных (в СУБД или файле 1CD) значительно увеличивает нагрузку на дисковую подсистему и оперативную память при любых операциях чтения. Мы настоятельно рекомендуем настроить хранение присоединенных файлов вне информационной базы:
После переноса картинок в тома СУБД перестанет раздуваться, а платформа 1С при формировании выгрузки будет последовательно считывать файлы с жесткого диска, не загружая тяжелые бинарные объекты в оперативную память через СУБД.
Если выгрузка пишется или дорабатывается вручную, критически важно переписать алгоритм так, чтобы выборка картинок происходила порционно, исключая их одновременное нахождение в памяти. Разберем правильный шаблон порционной обработки:
// ПРИМЕР ОПТИМИЗИРОВАННОГО ПОДХОДА
// Вместо одного запроса ко всей номенклатуре делаем порционный обход
РазмерПорции = 100;
ТекущийОфсет = 0;
Пока Истина Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ " + Строка(РазмерПорции) + "
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.ФайлКартинки КАК ФайлКартинки
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = ЛОЖЬ
| И Номенклатура.Ссылка ВЫБОРКА_ПО_ПОРЦИЯМ (Используйте фильтрацию по коду или ID)";
// Примечание: Для корректной порционной выборки используйте фильтрацию по ID больше предыдущего
// в целях упрощения примера логика смещения опущена.
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Прервать; // Все товары обработаны
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обрабатываем строго одну картинку, упаковываем ее и сразу очищаем переменные
ДвоичныеДанныеФайла = ПолучитьДвоичныеДанныеФайла(Выборка.ФайлКартинки);
Если ДвоичныеДанныеФайла <> Неопределено Тогда
ЗаписатьФайлВАрхив(ДвоичныеДанныеФайла, Выборка.Ссылка.Код);
КонецЕсли;
// Принудительно освобождаем память от тяжелых двоичных данных
ДвоичныеДанныеФайла = Неопределено;
КонецЦикла;
// Отправляем сформированную небольшую порцию на сайт
ОтправитьПакетНаСайт();
ОчиститьВременныйКаталогПакетногоОбмена();
КонецЦикла;
Очень часто контент-менеджеры загружают в 1С оригинальные фотографии товаров прямо с камер или фотостоков объемом 10–15 Мегабайт и разрешением свыше 5000 пикселей. Такое разрешение избыточно для сайта интернет-магазина и только перегружает серверы.
Мы можем встроить механизм автоматического сжатия изображений прямо перед их отправкой в zip-архив с помощью встроенных возможностей платформы 1С:
// Сжатие картинки "на лету" перед упаковкой
ИсходнаяКартинка = Новый Картинка(ПутьКФайлуНаДиске);
// Если картинка слишком большая, преобразуем ее разрешение
Если ИсходнаяКартинка.Ширина() > 1200 Или ИсходнаяКартинка.Высота() > 1200 Тогда
// Платформа выполнит масштабирование с сохранением пропорций
СжатаяКартинка = ИсходнаяКартинка.Преобразовать(ФорматКартинки.JPEG, 1200, 1200);
СжатаяКартинка.Записать(ПутьКВременномуФайлуСжатия);
КонецЕсли;
Даже если 1С успешно сформирует большой архив и отправит его без падения по памяти, принимающий веб-сервер сайта (Shop-Script) может заблокировать такой POST-запрос. Чтобы этого не произошло, необходимо проверить и скорректировать следующие параметры на хостинге или выделенном сервере сайта:
Параметр client_max_body_size 256M; (установите лимит в соответствии с максимально возможным весом вашего zip-пакета, например, 256 или 512 Мегабайт, иначе сервер вернет ошибку 413 Request Entity Too Large).
post_max_size = 256M (максимально допустимый размер данных, отправляемых методом POST).upload_max_filesize = 256M (максимальный размер загружаемого файла).memory_limit = 512M (объем оперативной памяти, выделяемый PHP-скрипту для распаковки и обработки архива на сайте).max_execution_time = 300 (время выполнения скрипта в секундах, так как импорт большого количества изображений требует времени).Таким образом, решив проблему комплексно — проверив размер отправляемого пакета с помощью Fiddler, перейдя на x64-разрядную версию платформы 1С, перенеся хранение файлов в тома на диске и ограничив аппетиты системы к оперативной памяти при помощи порционной обработки кода, мы получим стабильный и быстрый обмен данными с сайтом без сбоев и зависаний.