Как устранить взаимоблокировки (deadlocks) в 1С при обмене данными и записи документов?

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

Взаимоблокировка (deadlock) — это ситуация в работе СУБД, при которой две транзакции взаимно ожидают освобождения ресурсов, захваченных друг другом. В контексте 1С:Предприятия это часто происходит при работе распределенных информационных баз (РИБ) или при одновременной записи документов несколькими пользователями. Рассмотрим причины возникновения этой ошибки и разберем по шагам методы её устранения, основываясь на технических данных технологического журнала (ТЖ) и системных отчетах SQL Server.

Анализ причины проблемы: почему возникает конфликт?

Проанализируем ситуацию, описанную в технологическом журнале. Ошибка native=1205 прямо указывает на то, что Microsoft SQL Server выбрал транзакцию в качестве «жертвы» взаимоблокировки. В нашем случае конфликт происходит в момент работы регламентного задания обмена и интерактивной работы пользователя в форме документа ПоступлениеТоваров.

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

Особую сложность добавляет работа РИБ. При записи любого объекта (например, номенклатуры или документа) система автоматически делает запись в таблицу регистрации изменений (план обмена). Регламентное задание обмена в это же время может читать эту таблицу. Таким образом, возникают перекрестные захваты ресурсов таблиц объектов и таблиц регистрации изменений.

Решение 1: Программное повышение уровня блокировки (метод «ДЛЯ ИЗМЕНЕНИЯ»)

Самый быстрый способ предотвратить дедлок в автоматическом режиме — это принудительное повышение блокировки с разделяемой (S) до исключительной (U или X) в самом начале транзакции. Разберем, как это реализовать.

Вместо того чтобы позволить платформе сначала прочитать данные «просто так», мы выполним пустой запрос с конструкцией ДЛЯ ИЗМЕНЕНИЯ. Это заставит SQL Server сразу захватить ресурс в режиме, несовместимом с другими пишущими транзакциями. Посмотрим на пример кода, который необходимо разместить перед выполнением записи связанного объекта (например, характеристики или при регистрации в плане обмена):


Процедура ПередЗаписью(Отказ)
    // Устанавливаем блокировку на данные, которые могут быть изменены 
    // одновременно другим процессом (например, обменом)
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |   НоменклатураИзменения.Ссылка
    |ИЗ
    |   Справочник.Номенклатура.Изменения КАК НоменклатураИзменения
    |ГДЕ
    |   НоменклатураИзменения.Ссылка = &Ссылка
    |ДЛЯ ИЗМЕНЕНИЯ Справочник.Номенклатура.Изменения";
    
    Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Ссылка);
    Попытка
        Запрос.Выполнить();
    Исключение
        // Если здесь возникнет ошибка блокировки, транзакция просто подождет
    КонецПопытки;
КонецПроцедуры

Важный нюанс: этот запрос должен выполняться в рамках той же транзакции, в которой происходит основная запись. Если вы записываете подчиненный объект (например, ХарактеристикаНоменклатуры) из формы основного документа, рекомендуется явно открывать транзакцию:


НачатьТранзакцию();
Попытка
    // 1. Сначала блокируем 'намерения' изменения
    // (Код запроса ДЛЯ ИЗМЕНЕНИЯ)
    
    // 2. Затем выполняем запись
    ХарактеристикаНоменклатурыОбъект.Записать();
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

Решение 2: Переход на управляемый режим блокировок

Проанализируем более радикальный, но правильный с точки зрения архитектуры 1С способ — переход на управляемый режим блокировок. В этом режиме 1С использует уровень изоляции Read Committed Snapshot Isolation (RCSI) в SQL Server. Читающие транзакции больше не блокируют пишущие, так как читают данные из версий (tempdb).

Чтобы реализовать этот переход, выполним следующие шаги:

  1. В свойствах конфигурации установим свойство Режим управления блокировками данных в значение Управляемый (или Смешанный для постепенного перехода).
  2. На уровне СУБД проверим настройки базы данных. Выполним SQL-запрос для проверки включения механизма версионирования строк:
    
    SELECT name, is_read_committed_snapshot_on FROM sys.databases WHERE name = 'ИмяВашейБазы';
    
    Если значение в колонке 0, необходимо включить этот режим (требуется монопольный доступ к базе).
  3. Внимание! При переходе на управляемый режим необходимо вручную прописать объект БлокировкаДанных во всех критических узлах (проведение документов, контроль остатков), иначе система перестанет блокировать остатки, что приведет к их уходу в минус.

Решение 3: Оптимизация настроек SQL Server (MAXDOP)

Иногда взаимоблокировки могут носить внутренний характер СУБД (так называемые intra-query deadlocks), когда параллельные потоки одного и того же тяжелого запроса блокируют друг друга. Рассмотрим настройку MAXDOP (Maximum Degree of Parallelism).

Для баз данных 1С:Предприятия фирма «1С» рекомендует устанавливать MAXDOP = 1. Это гарантирует, что один запрос будет выполняться одним ядром процессора, что исключает целый класс дедлоков параллелизма. Проверить и изменить настройку можно в свойствах сервера в SQL Server Management Studio (раздел Advanced) или через скрипт:


EXEC sys.sp_configure N'show advanced options', N'1';
RECONFIGURE WITH OVERRIDE;
EXEC sys.sp_configure N'max degree of parallelism', N'1';
RECONFIGURE WITH OVERRIDE;

Практические советы по диагностике

Если ошибки продолжаются, рассмотрим способ получения графа взаимоблокировки без использования тяжелого профайлера. Воспользуемся механизмом Extended Events, который работает в SQL Server по умолчанию (сессия system_health):

Резюмируем: для устранения дедлоков в РИБ на старых платформах и обычных формах наиболее эффективным является сочетание программного метода ДЛЯ ИЗМЕНЕНИЯ для выравнивания порядка захвата ресурсов и технической настройки SQL Server (MAXDOP и RCSI). В долгосрочной перспективе рекомендуется переводить конфигурацию на управляемый режим блокировок данных.

← На главную