Почему при переходе с платформы 1С 8.2 на 8.3 стали появляться дедлоки и как это исправить

Программист 1С v8.3 (Обычные формы)
← На главную

При миграции старых конфигураций, таких как Управление производственным предприятием (УПП) 1.3, с платформы 8.2 на 8.3 программисты часто сталкиваются с неприятным сюрпризом: система, которая годами работала стабильно, начинает генерировать взаимные блокировки (deadlocks). Ситуация кажется парадоксальной, ведь режим управляемых блокировок уже был включен, а код не менялся. Разберем подробно, почему так происходит, и какие технические нюансы платформы 8.3 вызывают эти конфликты.

Различия в уровнях изоляции транзакций: Роль RCSI

Одной из главных причин появления дедлоков является изменение требований платформы к настройкам СУБД. Проанализируем механизм работы MS SQL Server в контексте 1С. Для корректной и производительной работы версии 8.3 критически важно использование режима Read Committed Snapshot Isolation (RCSI).

В чем заключается разница? Рассмотрим ситуацию:

  1. В версии 8.2 платформа могла работать с обычным уровнем изоляции Read Committed. В этом режиме операции чтения могли блокироваться операциями записи, и наоборот.
  2. В версии 8.3 механизмы управления сеансами и внутренними таблицами оптимизированы под версионность (Snapshot). Если режим RCSI не включен, чтение данных внутри транзакции начинает вызывать наложение S-блокировок (Shared locks) на уровне SQL, которые конфликтуют с X-блокировками (Exclusive) при записи.

Выясним причину, почему это ведет к дедлоку: транзакция №1 захватывает ресурс А для чтения, транзакция №2 захватывает ресурс Б для чтения. Затем №1 пытается записать в Б, а №2 — в А. Без RCSI они будут ждать друг друга вечно, пока SQL Server не принудительно завершит одну из них.

Чтобы проверить и включить этот режим, необходимо выполнить следующий скрипт в консоли SQL Management Studio:


ALTER DATABASE [Имя_Вашей_Базы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [Имя_Вашей_Базы] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [Имя_Вашей_Базы] SET MULTI_USER;

Парадокс гранулярности блокировок

Рассмотрим еще один важный аспект: почему раньше блокировок было "меньше"? На самом деле, их было больше, но они были "грубее". Платформа 8.2 зачастую накладывала блокировки на более широкие диапазоны данных или удерживала их дольше из-за менее совершенных алгоритмов планировщика.

В такой ситуации транзакции просто выстраивались в очередь. Первая транзакция блокировала "всю таблицу", а остальные ждали её завершения. В 8.3 механизмы стали более "тонкими" (гранулярными). Платформа старается блокировать только те записи, которые действительно нужны. Это повышает параллельность, но "обнажает" ошибки в последовательности захвата ресурсов в коде конфигурации.

Проанализируем классическую ситуацию дедлока в 1С:

В 8.2 одна из них, скорее всего, подождала бы другую целиком. В 8.3 они обе успешно выполнят первый шаг и "встретятся" на втором, вызвав дедлок. Решение здесь только одно — строгая регламентация порядка захвата ресурсов в коде.

Оптимизация кода внутри транзакций

Посмотрим на примеры из практики УПП 1.3. В старых допиленных конфигурациях часто встречаются огромные транзакции, внутри которых выполняются тяжелые запросы. Рассмотрим, как это лечится.

Ошибка: Выполнение запросов к базе данных в середине транзакции проведения, особенно если эти запросы не относятся к блокируемым данным напрямую.


Процедура ОбработкаПроведения(Отказ, Режим)
    Блокировка = Новый БлокировкаДанных;
    // ... установка блокировок ...
    Блокировка.Заблокировать();
    
    // ОШИБКА: Тяжелый запрос внутри транзакции
    Запрос = Новый Запрос("ВЫБРАТЬ ... ИЗ РегистрНакопления.ПартииТоваровНаСкладах"); 
    Результат = Запрос.Выполнить(); 
    
    // Запись движений
    Движения.Остатки.Записать();
КонецПроцедуры

Решение: Разберем по шагам правильный алгоритм. Все необходимые данные для проведения должны быть подготовлены ДО начала записи и установки управляемых блокировок. Выносите запросы за пределы захвата ресурсов, если это позволяет бизнес-логика. Если же данные должны быть актуальны именно в момент записи, используйте объект БлокировкаДанных для явного указания намерений.

Изменения в работе с временными таблицами

Платформа 8.3 иначе работает с временными таблицами на уровне СУБД. Она чаще создает индексы автоматически и по-другому формирует структуру в tempdb. В некоторых случаях это приводит к тому, что SQL Server делает вывод об эскалации блокировок (превращение блокировки строк в блокировку всей таблицы) быстрее, чем это делала 8.2.

Если вы видите дедлоки на системных ресурсах или в tempdb, проанализируйте свои запросы на предмет использования огромных временных таблиц без явного индексирования. В 8.3 рекомендуется явно индексировать поля временных таблиц, по которым в дальнейшем будет происходить соединение.

Влияние фоновых заданий

В 8.3 архитектура кластера существенно изменилась. Появилось множество служебных фоновых процессов, которые работают более агрессивно, чем в 8.2. Например:

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

Итоги и рекомендации

Подведем итог нашему анализу. Чтобы избавиться от дедлоков после перехода на 8.3, выполните следующие действия:

  1. Включите RCSI на уровне базы данных SQL. Это "золотое правило" для 8.3.
  2. Проверьте режим совместимости в свойствах конфигурации. Если он установлен в значение "Версия 8.2.16" и ниже, платформа будет пытаться эмулировать старое поведение, но это не всегда спасает от конфликтов блокировок.
  3. Оптимизируйте порядок захвата ресурсов. Все документы в системе должны блокировать регистры в одинаковой последовательности (например, всегда сначала Остатки, затем Партии, затем Бухгалтерский).
  4. Сократите время транзакций. Выносите все проверки и подготовки данных "вверх" по стеку вызовов, до момента начала записи объекта.

Помните, что появление дедлоков в 8.3 — это не ошибка платформы, а сигнал о том, что ваш код содержит потенциальные конфликты, которые раньше просто маскировались низкой производительностью и очередями.

← На главную