Почему HTTP-сервис 1С в файловой базе зависает после нескольких запросов или операций записи?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции внешних систем с информационной базой 1С через HTTP-сервисы разработчики нередко сталкиваются с ситуацией, когда первые вызовы метода отрабатывают штатно, а затем сервис намертво зависает. При этом подключение остается висеть в активных сеансах, обработчик метода перестает вызываться, а веб-сервер IIS выдает системную ошибку о том, что рабочий процесс не смог остановить канал прослушивателя для протокола HTTP в отведенный интервал времени.

Ситуация осложняется тем, что попытка перехватить ошибку стандартной конструкцией Попытка ... Исключение не срабатывает — сервис зависает непосредственно в момент вызова метода Записать(). Разберем по шагам, почему возникает эта проблема в файловом режиме и какими способами ее можно устранить.

Выясним причину: особенности работы файловой базы под IIS

Проанализируем техническую сторону взаимодействия веб-сервера Internet Information Services (IIS) и файловой СУБД платформы 1С:

  1. Блокировки файла базы данных на уровне ядра ОС. В файловом режиме модуль веб-расширения wsisapi.dll выполняется внутри рабочего процесса IIS (w3wp.exe). Файловая база управляет доступом к данным посредством системных блокировок диапазонов байт в файле 1Cv8.1CD. Если входящие HTTP-запросы приходят плотным потоком или в цикле выполняется множество одиночных записей, потоки процесса начинают конкурировать за файловый дескриптор. Происходит взаимоблокировка (deadlock) на уровне операционной системы, которую код 1С перехватить не может.
  2. Каскадные одиночные транзакции. Когда метод Записать() вызывается без явного открытия транзакции, платформа на каждую итерацию открывает неявную транзакцию, фиксирует изменения и выполняет сброс буферов на диск. При нескольких сотнях таких вызовов файловая подсистема перегружается операциями ввода-вывода.
  3. Зависание сеансов в пуле соединений. Параметр reuseSessions="autouse" в конфигурационном файле публикации default.vrd заставляет веб-сервер удерживать сеансы в оперативной памяти. Если один из потоков завис в ожидании снятия блокировки с файла базы данных, сеанс из пула не освобождается. По достижении предела poolSize все последующие запросы становятся в бесконечную очередь.
  4. Сбой рециклинга пула приложений. Пытаясь перезапустить зависший пул по таймауту, IIS не может корректно завершить процесс w3wp.exe, так как системные потоки удерживают открытый файл базы данных. В результате порт блокируется, и сервер прекращает обработку входящего трафика.

Решение 1. Оптимизация записи и группировка в явную транзакцию

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


Функция ШаблонURL1Example(Запрос)
    СтрокаОтвет = "Успех!";    
    Для Сч = 1 по 300 Цикл
        Запись = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
        Запись.Период = Дата(2017, 1, 1);
        Запись.Валюта = Константы.ВалютаРегламентированногоУчета.Получить();
        Запись.Курс = 1;
        Запись.Кратность = 1;
        Попытка
            Запись.Записать();
        Исключение
            СтрокаОтвет = "Запись не удалась. Попытка № " + Сч + ". " + ОписаниеОшибки();
            Прервать;            
        КонецПопытки;                
    КонецЦикла;    
    
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.УстановитьТелоИзСтроки(СтрокаОтвет);
    Возврат Ответ;
КонецФункции

В этом коде 300 раз подряд захватывается и освобождается файл 1Cv8.1CD. Чтобы устранить конкуренцию и снизить нагрузку на дисковую подсистему, объединим весь массив операций в одну явную транзакцию с помощью методов НачатьТранзакцию() и ЗафиксироватьТранзакцию(), а также поместим блок перехвата ошибок снаружи цикла:


Функция ШаблонURL1Example(Запрос)
    СтрокаОтвет = "Успех!";
    СчСервиса = 0;
    
    НачатьТранзакцию();
    Попытка
        Для Сч = 1 По 300 Цикл
            СчСервиса = Сч;
            Запись = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
            Запись.Период = Дата(2017, 1, 1);
            Запись.Валюта = Константы.ВалютаРегламентированногоУчета.Получить();
            Запись.Курс = 1;
            Запись.Кратность = 1;        
            Запись.Записать();
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
        Ответ = Новый HTTPСервисОтвет(200);
        Ответ.УстановитьТелоИзСтроки(СтрокаОтвет);
    Исключение
        ОтменитьТранзакцию();
        СтрокаОтвет = "Запись не удалась на итерации № " + СчСервиса + ". " + ОписаниеОшибки();
        Ответ = Новый HTTPСервисОтвет(500);
        Ответ.УстановитьТелоИзСтроки(СтрокаОтвет);
    КонецПопытки;                
    
    Возврат Ответ;
КонецФункции

Такой подход сокращает количество операций блокировки на уровне диска с сотен до единичного вызова, что предотвращает появление дедлоков операционной системы.

Решение 2. Тонкая настройка пула приложений IIS и файла default.vrd

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

  1. Изоляция пула приложений. Выделим для публикации 1С отдельный пул (например, 1C_Pool) и уберем ее из общего пула DefaultAppPool.
  2. Ограничение числа процессов. В дополнительных параметрах пула проверим параметр Максимальное число рабочих процессов (Max Worker Processes). Он должен быть строго равен 1. Использование веб-сада (Web Garden) при файловой базе недопустимо, так как два независимых процесса w3wp.exe не могут одновременно разделять монопольный доступ к файлу базы.
  3. Отключение управляемого кода. Установим параметр Версия среды .NET CLR в значение Без управляемого кода (No Managed Code), поскольку библиотека wsisapi.dll является нативным модулем C++.
  4. Отключение кэширования профиля. Установим параметр Загрузить профиль пользователя (Load User Profile) в значение False для снижения блокировок системного реестра.
  5. Управление сеансами в default.vrd. В файле публикации изменим режим повторного использования сеансов:
    
    <service name="CRMIntegration"
             rootUrl="CRMIntegration"
             enable="true"
             reuseSessions="dontuse"/>
    
    Параметр reuseSessions="dontuse" заставляет сервис завершать сеанс после отдачи ответа клиенту. Это предотвращает утечку зависших подключений в пуле, хотя и создает небольшие накладные расходы на инициализацию контекста при каждом запросе.

Решение 3. Переход на веб-сервер Apache

Практика показывает, что многопоточная модель взаимодействия модуля wsisapi.dll с файловой СУБД 1С под управлением IIS часто оказывается нестабильной при высокой частоте запросов. Перенос публикации на веб-сервер Apache HTTP Server (версии 2.4) с модулем mod_1c.so решает проблему зависания без необходимости переписывать алгоритмы интеграции. Модуль Apache иначе управляет потоками и блокировками дескрипторов файлов базы, что обеспечивает стабильную работу даже при серийной записи данных в файловую базу.

Архитектурные рекомендации

Для долговременной стабильности интеграций рассмотрим следующие рекомендации:

  1. Исключения антивируса. Убедимся, что каталог с информационной базой и расширение *.1CD добавлены в список исключений антивирусного сканера и службы индексации Windows Search, которые часто перехватывают дескрипторы файлов в момент интенсивной записи.
  2. Асинхронный прием данных. Для файловых баз оптимальным решением является перенос тяжелой логики проведения и записи в фоновые процессы. HTTP-сервис должен быстро сохранить входящий JSON или XML в буфер (например, в текстовый файл или отдельную простую очередь) и сразу вернуть статус 200 OK, а разбор и запись в базу должны выполняться регламентным заданием в один поток.
  3. Переход на клиент-серверный вариант (SQL). Если объем запросов к HTTP-сервису постоянно растет, файловый режим исчерпывает свои возможности из-за табличных блокировок. В клиент-серверном варианте обработку запросов берут на себя рабочие процессы rphost, а блокировки переходят на уровень строк СУБД, что полностью исключает зависание веб-сервера.
← На главную