Как решить проблему зависания сеансов 1С и бесконечной генерации событий SDBL?

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

Каждый администратор крупных информационных систем на базе платформы «1С:Предприятие» рано или поздно сталкивается с ситуацией, когда один или несколько пользователей начинают испытывать сильнейшие задержки при работе («тормоза»), хотя остальные коллеги работают в штатном режиме. При этом нагрузка на процессоры сервера СУБД или сервера приложений возрастает до 30-40%, а в технологическом журнале регистрируется непрерывный, лавинообразный поток событий SDBL. Самое странное заключается в том, что поток запросов не прекращается, даже если пользователь отошел от компьютера и сеанс находится в состоянии полного простоя.

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

Что такое SDBL и почему он может «залипать» в простое?

Прежде чем перейти к практике, проанализируем внутренние механизмы платформы. Аббревиатура SDBL расшифровывается как System Database Layer — это собственный внутренний слой платформы 1С, который выступает посредником между объектной моделью метаданных (документы, справочники, регистры) и реляционной базой данных (MS SQL Server, PostgreSQL и др.). Именно SDBL транслирует запросы, написанные на встроенном языке 1С, в SQL-запросы, понятные конкретной СУБД.

Когда пользователь активно работает с базой данных (проводит документы, открывает отчеты), генерация событий SDBL — это абсолютно нормальный процесс. Каждое такое событие сопровождается контекстом выполнения (событие Context в технологическом журнале), указывающим на конкретную строку кода в модуле.

Однако если пользователь бездействует, а цепь событий SDBL продолжает бесконечно генерироваться без пауз, это сигнализирует об аномалии. Рассмотрим основные причины такого поведения:

  1. Циклические вызовы во внешних интеграциях и фоновых задачах. Очень часто для обмена данными с государственными системами (ЕГАИС, Меркурий/ВетИС, Честный Знак) или внешними сервисами разработчики пишут процедуры, которые запускаются в контексте клиентского сеанса. Если такая интеграция была выведена из эксплуатации, но ее вызовы не были корректно удалены из кода, система может бесконечно пытаться отправить запрос или проверить статус, зацикливаясь в конструкции Попытка — Исключение.
  2. Неоптимальные обработчики ожидания. Метод ПодключаемыйОбработчикОжидания позволяет запускать процедуры с определенным интервалом времени. Если внутри обработчика выполняется тяжелый запрос к базе данных, время выполнения которого превышает интервал самого таймера, запросы начинают наслаиваться друг на друга, порождая бесконечный поток SDBL.
  3. Автообновление динамических списков. Если на открытой у пользователя форме (например, в рабочем столе логиста или диспетчера отгрузки) настроено автообновление сложного динамического списка с кучей левых соединений и виртуальных таблиц, СУБД будет непрерывно пересчитывать эти данные.
  4. Бесконечные попытки проведения или записи в фоновом режиме. Сбои в механизмах блокировок или некорректно обработанные транзакции могут приводить к тому, что транзакция постоянно откатывается и запускается заново.

Шаг 1. Тонкая настройка технологического журнала для нескольких ПК

Для локализации проблемы нам потребуется собрать технологический журнал (ТЖ). Однако собирать логи со всего сервера приложений — не лучшая идея, так как файлы ТЖ моментально забьют дисковое пространство гигабайтами мусора. Нам нужно ограничить сбор информации только проблемными компьютерами (например, машинами с сетевыми именами exp и exp2).

Выясним важную деталь синтаксиса файла logcfg.xml. Все условия отбора, прописанные внутри одного тега <event>, объединяются по логическому «И» (AND). Соответственно, мы не можем написать два отбора по имени компьютера внутри одного тега <event>, так как событие не может происходить на двух компьютерах одновременно. Для реализации логического «ИЛИ» (OR) нам необходимо создать несколько отдельных блоков <event> внутри одного тега <log>.

Рассмотрим правильный пример конфигурационного файла logcfg.xml:


<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
  <log location="C:\v8\logs\sdbl_heavy" history="12">
    <!-- Отслеживаем события SDBL для компьютера exp -->
    <event>
      <eq property="name" value="SDBL"/>
      <eq property="t:computerName" value="exp"/>
    </event>
    <!-- Отслеживаем события SDBL для компьютера exp2 -->
    <event>
      <eq property="name" value="SDBL"/>
      <eq property="t:computerName" value="exp2"/>
    </event>
    <!-- Сюда же обязательно добавляем сбор контекста для этих машин -->
    <event>
      <eq property="name" value="Context"/>
      <eq property="t:computerName" value="exp"/>
    </event>
    <event>
      <eq property="name" value="Context"/>
      <eq property="t:computerName" value="exp2"/>
    </event>
    <property name="all"/>
  </log>
</config>

Эта настройка позволит нам получить чистый лог, содержащий информацию только по двум потенциально проблемным рабочим станциям. Параметр history="12" ограничит хранение логов двенадцатью часами, защитив диск от переполнения.

Шаг 2. Анализ СУБД в момент зависания

Когда у пользователя снова начнутся тормоза, нам необходимо зафиксировать активность на уровне системы управления базами данных (например, MS SQL Server). Для этого воспользуемся встроенным средством Activity Monitor (Монитор активности) в SQL Server Management Studio (SSMS) или запустим трассировку через Extended Events.

Нам нужно отфильтровать процессы по имени базы данных 1С и найти идентификатор сессии (SPID), который потребляет аномально много ресурсов процессора или выполняет огромное число операций чтения (Logical Reads). Зафиксировав SQL-текст запросов, мы сможем понять, к каким именно таблицам идет обращение. Например, в SQL-запросе могут фигурировать таблицы документов вида _Document150 или регистров сведений _InfoReg20345.

Сопоставить эти физические таблицы СУБД с метаданными 1С можно с помощью получением структуры хранения БД через встроенную функцию платформы:


// Получаем соответствие имен таблиц в СУБД объектам метаданных
СтруктураБазы = ПолучитьСтруктуруХраненияБазыДанных();

Шаг 3. Локализация и устранение проблемы в коде

После сопоставления SQL-запросов с метаданными 1С мы переходим к анализу собранного технологического журнала. Ищем повторяющиеся блоки событий SDBL и анализируем предшествующие им события Context. Контекст четко укажет на строку кода встроенного языка, которая инициировала этот цикл.

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

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


// Пример устаревшего и опасного кода во внешнем модуле
Процедура ПроверитьСтатусыСертификатов() Экспорт
    // Алгоритм пытается обработать массив документов в бесконечном цикле
    Пока Истина Цикл
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ ПЕРВЫЕ 10
            |	ВетПаспорт.Ссылка КАК Ссылка
            |ИЗ
            |	Справочник.ВетеринарныеДокументы КАК ВетПаспорт
            |ГДЕ
            |	ВетПаспорт.СтатусОбмена = ЗНАЧЕНИЕ(Перечисление.СтатусыВыгрузки.Подготовлено)";
        
        Выборка = Запрос.Выполнить().Выбрать();
        
        Если НЕ Выборка.Следующий() Тогда
            // Если документов нет, выходим из цикла
            Прервать; 
        КонецЕсли;
        
        // Попытка отправить запрос во внешнюю систему, которая уже отключена
        Попытка
            ВыгрузитьДанныеВоВнешнийСервис(Выборка.Ссылка);
        Исключение
            // Ошибка перехватывается, но прерывания цикла нет! 
            // В итоге мы получаем бесконечный цикл и лавину SDBL запросов.
            ЗаписьЖурналаРегистрации("Интеграция", УровеньЖурналаРегистрации.Предупреждение,,, "Ошибка связи");
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

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

Решение проблемы: необходимо полностью удалить или закомментировать («зарэмить») вызовы неиспользуемых устаревших интеграций, отключить неактуальные регламентные задания и обработчики ожидания. После комментирования проблемного участка кода бесконечный поток SDBL прекратится, нагрузка на процессоры сервера упадет, а сеансы пользователей перестанут зависать.

Дополнительные рекомендации по профилактике

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

← На главную