Почему возникает длительное ожидание на блокировке в 1С и как правильно читать отчеты мониторинга?

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

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

Разберем детально, как устроена механика фиксации блокировок, что на самом деле означает показатель длительности в аналитических инструментах, а также выясним основные причины возникновения конфликтов блокировок и способы их устранения.

Интерпретация показателя длительности в мониторинге блокировок

Главная причина непонимания ситуации кроется в трактовке колонок отчетов технологического журнала и систем мониторинга:

  1. Колонка «Длительность» (Duration): отображает время, в течение которого транзакция ожидала возможности установить блокировку на ресурс, а не общее время удержания этой блокировки или длительность всей транзакции.
  2. Поведение виновника: если у виновника указана длительность 0,0001 сек, это означает лишь то, что он захватил ресурс практически мгновенно и без конкурентного ожидания. Однако сама исключительная блокировка продолжает удерживаться виновником вплоть до завершения его транзакции (команды ЗафиксироватьТранзакцию() или окончания обработчика проведения).
  3. Поведение жертвы: транзакция-жертва пытается получить доступ к тому же диапазону данных или таблице, но наталкивается на несовместимый тип блокировки и ожидает завершения транзакции виновника до момента успешного захвата или до истечения таймаута блокировки.

Основные причины длительных блокировок и таймаутов

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

  1. Отключенный режим версионирования строк на СУБД MS SQL Server: в управляемом режиме блокировок 1С крайне важно, чтобы чтение данных не конфликтовало с операциями записи на уровне СУБД. Если параметры is_read_committed_snapshot_on и snapshot_isolation_state_desc отключены (равны 0 / OFF), MS SQL Server накладывает разделяемые S-блокировки при чтении, провоцируя конфликты страниц и эскалацию блокировок даже при корректной логике кода 1С.
  2. Длительная транзакция виновника: установка блокировки происходит в начале алгоритма, после чего внутри открытой транзакции выполняются тяжелые запросы, перебор больших массивов данных, расчет себестоимости или вызовы внешних веб-сервисов.
  3. Конкуренция в алгоритмах контроля остатков и списания партий: вызовы процедур вида УпорядочитьТаблицуПоДокументу, списание по ФИФО или контроль последовательностей при параллельном проведении документов по одним и тем же аналитическим разрезам (организация, склад, номенклатура).
  4. Избыточно широкие пространства блокировок: наложение исключительных блокировок без точной фильтрации по ключевым измерениям, в результате чего блокируются целые таблицы или широкие диапазоны записей регистра.

Пошаговые способы устранения проблемы

Рассмотрим комплекс мер, направленных на оптимизацию параллельной работы и исключение таймаутов.

1. Включение READ_COMMITTED_SNAPSHOT на MS SQL Server

Переведем рабочую базу данных в режим версионирования строк, чтобы операции чтения не блокировали операции записи на уровне СУБД. Для этого выполним команду в консоли SQL Server Management Studio:


ALTER DATABASE [ИмяБазыДанных] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;

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


SELECT name, is_read_committed_snapshot_on, snapshot_isolation_state_desc
FROM sys.databases
WHERE name = 'ИмяБазыДанных';

Значение is_read_committed_snapshot_on должно стать равным 1.

2. Настройка сбора технологического журнала

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


<log location="C:\LOGS\Locks" history="24">
    <event>
        <eq property="name" value="TLOCKS"/>
    </event>
    <event>
        <eq property="name" value="TTIMEOUT"/>
    </event>
    <event>
        <eq property="name" value="TDEADLOCK"/>
    </event>
    <property name="all"/>
</log>

Это позволит сопоставить момент начала транзакции виновника, захват ресурса и фактическое время вызова фиксации транзакции.

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

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


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Организация", Шапка.Организация);
ЭлементБлокировки.УстановитьЗначение("Склад", Шапка.Склад);
ЭлементБлокировки.ИсточникДанных = ТаблицаТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();

4. Сокращение длительности открытых транзакций

Соблюдаем ключевые правила при проектировании транзакционной логики:

  1. Выносим все ресурсоемкие выборки, проверки корректности заполнения реквизитов и подготовительные расчеты за пределы транзакции.
  2. Категорически исключаем синхронные обращения к сетевым каталогам, веб-сервисам и сторонним API внутри тела транзакции.
  3. Включаем разделение итогов для часто обновляемых регистров накопления и регистров бухгалтерии, чтобы снизить конкуренцию за итоговые таблицы.
  4. При массовой обработке и перепроведении документов разбиваем общую транзакцию на порции и используем механизмы отложенного проведения в фоновых заданиях.
← На главную