Книга: Настольная книга 1С:Эксперта по технологическим вопросам
Назад: Таймаут
Дальше: 3.10.Эскалация блокировок

Взаимоблокировка (deadlock)

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

Иначе говоря, сущность взаимоблокировок в следующем: Светочка ждет Леночку, а Леночка ждет Светочку. Замкнутый круг. Решается только принудительным внешним воздействием.

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

Возникновение взаимоблокировок сводят к следующим ситуациям.

1. Захват ресурсов в разном порядке. X1 -> X2, X2-> X1.

Светочке сказали: распишись сначала в договоре, потом в приложении и потом отдай оба листа. Леночке сказали несколько иначе: распишись сначала в приложении, потом в договоре и потом отдай оба листа.

Если девушки будут работать по очереди, ничего страшного не произойдет. Если же они начнут работать одновременно, то ни одна из них не сможет завершить задачу: им не сказано «отдавать один лист», сказано – «отдать оба».

В такой постановке это в чистом виде ошибка организации работы. Исправляется она организацией доступа к ресурсам в одинаковом порядке. Переходя к «1С», если есть такие подозрения, порядок доступа можно проверить (без использования ЦУП), например, через подписку на событие ПриЗаписи наборов записей всех регистров, тем или иным образом выводя сообщения об имени регистра, в который идет запись, и сравнивая последовательно записанные протоколы для разных типов документов.

Особый случай этой же ситуации: чтение общей области после раздельной записи. X1 -> S12, X2 ->S12.

Светочке сказали: распишись в договоре, потом прочитай и отдай оба листа. Леночке сказали: распишись в приложении, потом прочитай и отдай оба листа.

Леночка и Светочка изменяют разные документы. Но потом им требуются ресурсы друг друга, как правило, объединенные вместе.

В системах на платформе «1С:Предприятие» эти взаимоблокировки стали часто возникать после появления технологии разделения итогов, и происходит это чаще всего в двух случаях:

Движения.Хозрасчетный.БлокироватьДляИзменения = Истина;

Движения.Хозрасчетный.Записать();

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

Особо обращаем внимание на то, что технически работа свойства БлокироватьДляИзменения реализована с помощью установки управляемой блокировки. В автоматическом режиме управления блокировками попытка использования БлокироватьДляИзменения не игнорируется (в отличие от ДЛЯ ИЗМЕНЕНИЯ в управляемом режиме), а приводит к исключительной ситуации. При этом разделитель итогов на уровне СУБД работает, т. е. возможна параллельная запись совпадающих наборов.

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

Однако на этом все не заканчивается.

На другой день Светочка и Леночка изменяют каждая только свои документы. И каждая из них хочет принести начальнику на проверку всю стопку (обе собираются установить избыточную блокировку – не важно, исключительную или разделяемую).

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

2. Повышение уровня блокировки ресурса. S1 -> X1, S1-> X1.

Светочка подошла к столу и начала читать документ. Сразу за этим к столу подошла Леночка и начала читать тот же документ. Светочка увидела, что ей надо внести в этот документ изменения, и хотела было его унести к себе, но Леночка ей не дала: она еще его не дочитала. А затем и Леночка увидела, что ей тоже надо внести в этот документ изменения, и тоже хотела было его унести к себе, но теперь уже Светочка не дала ей этого сделать.

Эта ситуация, когда один и тот же ресурс блокируется сначала разделяемой блокировкой, а затем исключительной, и при параллельном обращении к этому ресурсу возникает взаимоблокировка, характерна для режима автоматического управления блокировками «1С». В этом режиме используются уровни изоляции транзакции Serializable и Repeatable Read, и разделяемые блокировки не снимаются после чтения, а остаются до конца транзакции. Но и в управляемом режиме можно получить тот же эффект, поставив явную разделяемую блокировку на данные, на которые затем явно или неявно будет установлена исключительная блокировка.

Для обхода этой взаимоблокировки в SQL Server был введен особый уровень блокировки: U (Update), см. раздел . Этот уровень совместим только с разделяемыми блокировками S, но сам с собой уже нет. Чтобы его задействовать, в запрос на языке запросов «1С» необходимо добавить опцию ДЛЯ ИЗМЕНЕНИЯ, при этом не забыв указать, какие таблицы блокировать, иначе запрос поставит эту блокировку на все таблицы, задействованные в нем.

Если такая взаимоблокировка возникла на блокировках «1С», то перед чтением данных ресурса, в который потом будет идти запись, нужно ставить исключительную блокировку. Если разделяемая блокировка ставится явно и чтение производится на языке запросов, а не через объектную модель, нужно заменить ее сразу на исключительную блокировку.

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

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

К сожалению, все это не гарантирует, что взаимоблокировок не будет. Нет методики, которая даст 100 % гарантию их отсутствия. Поэтому нужно уметь расследовать и устранять взаимоблокировки.

В заключение еще об одном виде взаимоблокировок. Они могут возникать в СУБД Microsoft SQL Server и характеризуются следующими сообщениями об ошибке:

Причиной является то, что при работе на многопроцессорном компьютере Microsoft SQL Server может попытаться распараллелить процесс выполнения запроса на несколько процессоров. Обычно это происходит в том случае, если план запроса неоптимален. При параллельном выполнении нескольких частей одного запроса на разных процессорах возможна взаимоблокировка.

Для решения проблемы необходимо установить значение параметра max degree of parallelism («Максимальная степень параллелизма») равным 1 ? SQL Management studio, свойства SQL server, закладка Дополнительно.

Другим способом решения проблемы является оптимизация исполняемого запроса.

Взаимоблокировки имеют характерную особенность поведения: при высокой интенсивности работы они появляются большими группами – по пять-шесть штук подряд. Это связано с тем, что, когда две транзакции зацепились, об них спотыкаются еще несколько, и образуется куча-мала. Значимость ЦУП для расследования подобных ситуаций переоценить сложно.

Назад: Таймаут
Дальше: 3.10.Эскалация блокировок