Приветствуем вас! В процессе разработки на платформе 1С:Предприятие 8 часто возникает классическая проблема: передача относительно небольшого объема данных (например, массива из 20 000 ссылок на документы, который физически весит не более 700-800 Кб) с сервера на клиент занимает непозволительно много времени — вплоть до нескольких минут. На первый взгляд это кажется парадоксом, ведь современные сети должны передавать такой объем практически мгновенно.
В этой статье мы подробно проанализируем эту ситуацию, выявим скрытые механизмы платформы 1С, которые приводят к «зависанию» системы, и рассмотрим по шагам, как решить эту проблему раз и навсегда.
Когда мы передаем с сервера массив, содержащий элементы типа ДокументСсылка.ЗаказПокупателя, сама передача ссылок (которые по сути являются уникальными идентификаторами UUID) действительно происходит быстро. Проблемы начинаются тогда, когда клиентское приложение начинает работать с этим массивом на своей стороне. Любая попытка обратиться к реквизиту ссылки на клиенте приводит к катастрофическому падению производительности.
Разберем, что происходит при следующем коде на стороне клиента:
Для Каждого ЭлементИзМассива Из ПолученныйМассив Цикл
ТекстПредставления = Строка(ЭлементИзМассива); // Неявный вызов сервера!
Если ЭлементИзМассива.Проведен Тогда // Еще один неявный вызов сервера!
// Выполнение логики
КонецЕсли;
КонецЦикла;
При каждом обращении к свойству ссылки (например, Проведен, Дата, Номер) или при попытке получить строковое представление через функцию Строка(), платформа 1С выполняет синхронный неявный вызов сервера для получения этих данных из базы данных. Для 20 000 элементов это означает 20 000 отдельных сетевых запросов типа «туда-обратно». Даже при идеальном пинге локальной сети в 2 мс суммарное время ожидания составит не менее 40 секунд. Если же пользователи подключены удаленно (через VPN или медленный интернет), этот процесс легко растягивается на 5-10 минут.
Решение проблемы: Никогда не передавайте «голые» ссылки на клиент, если там планируется чтение их реквизитов или вывод представлений. Вместо этого сформируйте на сервере массив легких структур, содержащих все необходимые текстовые и числовые значения:
&НаСервереБезКонтекста
Функция ПолучитьДанныеЗаказовНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Ссылка,
| ЗаказПокупателя.Номер КАК Номер,
| ЗаказПокупателя.Дата КАК Дата,
| ЗаказПокупателя.Проведен КАК Проведен
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя";
РезультатВыгрузки = Запрос.Выполнить().Выгрузить();
МассивДанных = Новый Массив;
Для Каждого Строка Из РезультатВыгрузки Цикл
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("Ссылка", Строка.Ссылка);
СтруктураДанных.Вставить("Представление", Строка(Строка.Ссылка));
СтруктураДанных.Вставить("Номер", Строка.Номер);
СтруктураДанных.Вставить("Дата", Строка.Дата);
СтруктураДанных.Вставить("Проведен", Строка.Проведен);
МассивДанных.Добавить(СтруктураДанных);
КонецЦикла;
Возврат МассивДанных;
КонецФункции
Очень часто разработчики вызывают серверные методы формы, используя стандартную директиву компиляции &НаСервере. Выясним, почему это приводит к сильным задержкам.
При вызове контекстной серверной процедуры платформа вынуждена сериализовать и передать на сервер абсолютно весь контекст текущей формы: значения всех реквизитов, данные табличных частей, состояние элементов управления и прочее. После выполнения процедуры весь этот массив информации упаковывается обратно и отправляется на клиент. Если на форме отображается тяжелая таблица с тысячами строк, то даже простой возврат булевого значения или небольшого массива через контекстный метод вызовет огромный сетевой трафик и нагрузку на процессор.
Решение проблемы: Всегда используйте директиву &НаСервереБезКонтекста для функций, которые просто получают данные из базы и возвращают их на клиент. Это полностью исключает накладные расходы на передачу контекста формы, так как на сервер передаются только параметры, явно указанные в скобках вызова.
При передаче сложных объектов, таких как ТаблицаЗначений, ДеревоЗначений или даже больших массивов структур, платформа осуществляет их сериализацию в формат XML (через внутренние механизмы XDTO). Процесс разбора XML-пакетов на клиенте является однопоточным и сильно нагружает центральный процессор клиентской машины.
Проанализируем две альтернативные стратегии оптимизации сериализации данных:
ЗаписатьJSON и быстро восстановить его на клиенте через ПрочитатьJSON.ПоместитьВоВременноеХранилище, а на клиент верните легкую строку-адрес (UUID).Посмотрим на пример эффективного использования временного хранилища:
&НаСервереБезКонтекста
Функция ПоместитьМассивВХранилище()
МассивСсылок = Новый Массив; // Допустим, здесь 20 000 ссылок
// Код заполнения массива...
АдресХранилища = ПоместитьВоВременноеХранилище(МассивСсылок, Новый УникальныйИдентификатор);
Возврат АдресХранилища; // Возвращаем только короткую строку-адрес
КонецФункции
В гетерогенных сетях, где сервер 1С функционирует под управлением ОС Linux, а клиенты работают на ОС Windows, нередко возникают специфические сетевые задержки при передаче больших пакетов данных.
Разберем основные системные проблемы и способы их устранения:
/etc/hosts на сервере 1С или отключение DNS-резолва в настройках сети Linux.
netsh int tcp set global autotuninglevel=disabled
При передаче больших объемов данных между сервером и клиентом 1С генерирует интенсивный поток XML/XDTO данных через сетевые порты рабочих процессов (диапазон 1540-1591). Многие современные антивирусные системы со встроенными сетевыми экранами (Firewall) и веб-фильтрами пытаются перехватить этот поток для анализа «на лету».
Для больших пакетов данных такой анализ создает колоссальную задержку, так как антивирусу требуется накопить пакет в буфере, распаковать его и проверить. Решением является добавление процессов 1С (1cv8.exe, 1cv8c.exe) и используемых сетевых портов в список исключений сканирования вашего антивирусного программного обеспечения.
Подводя итоги, отметим, что скорость клиент-серверного взаимодействия в 1С зависит не столько от физического объема данных, сколько от выбранной архитектуры решения. Минимизируйте контекстные вызовы, избавляйтесь от неявного разыменования ссылок на клиенте и используйте временное хранилище — это позволит вашей системе работать максимально быстро и отзывчиво!