Deadlocks

Взаимные блокировки (Deadlock).

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

Deadlock можно назвать классической проблемой транзакционных баз данных. Это, даже не проблема, а просто рабочий момент и не повод для беспокойства. Поводом для беспокойства могут стать слишком частые deadlock-и, в результате чего транзакции не могут нормально выполняться, и работа приложения может остановиться. Как правило, в случае возникновения такой ситуации следует обратиться к программистам, поддерживающих данное приложение.

Основные причины возникновения deadlock-ов:

  • Транзакции накладывают блокировки на одинаковые таблицы, но в обратном порядке.
  • команды UPDATE и SELECT…FOR UPDATE в различных транзакциях на первом шаге устанавливают блокировку каких-либо данных и затем вторым шагом пытаются выставить следующую блокировку. При этом первая транзакция пытается заблокировать данные уже заблокированные второй транзакцией перед этим, а вторая транзакция наоборот пытается выставить блокировку на данные, уже заблокированые в первой транзакции.
  • Несколько транзакций ждут друг друга по кругу. Например, транзакция Т1 ждет транзакцию Т2, Т2 ждет Т3, а Т3 – Т1.

Чтобы уменьшить вероятность возникновения взаимных блокировок разнаботчики MySQL рекомендуют:

  • Чаще выполнять COMMIT, проверять в приложении ошибки и в случае обнаружения deadlock проводить заново откатившуюся транзакцию.
  • Использовать небольшие транзакции (т.е. небольшое количество строк вставляется, удаляется или изменяется). В первую очередь, чтобы избежать откатов (rollback) больших изменений.
  • Осуществлять доступ к таблицам и строкам в определенном порядке.
  • Добавить хорошо продуманные индексы на таблицы.
  • Использовать меньше блокировок или устанавливать ниже уровень изоляции транзакций (например, READ COMMITTED).

Для того, чтобы понять причины взаимных блокировок можно использовать:

  • Команду SHOW ENGINE INNODB STATUS, которая выдаст информацию по самому последнему dtadlock-у.
  • перезапустить MySQL сервер c включенным параметром innodb_print_all_deadlocks (начиная с версии 5.5.30). В этом случае информация о всех deadlock-ах будет попадать в error.log.

Следует отметить еще одну особенность отката транзакций при возникновении deadlock-ов. Когда InnoDB осуществляет откат текущей транзакции, все блокировки освобождаются. Однако это касается простых SQL команд. Некоторые блокировки могут все-таки остаться. Например, если в команде SELECT вызывается какая-то функция, в которой устанавливаются блокировки, а после этой команды SELECT случается deadlock и откат транзакции.

И в заключении классический пример, как можно получить deadlock:

Сессия 1 Сессия 2
s1> START TRANSACTION;S1> UPDATE PERSONS
SET LAST_NAME = ‘IVANOV’ WHERE ID=5;
s2> START TRANSACTION;s2> UPDATE PERSONS
SET LAST_NAME = ‘PETROV’ WHERE ID=7;
s1> DELETE FROM PERSONS WHERE LAST_NAME = ‘PETROV’;
s2>UPDATE PERSONS
SET FIRST_NAME = ‘STEPAN’ WHERE ID=5;ERROR 1213 (40001) : Deadlock found when trying to get lock; try restarting transaction
 Query OK, 1 row affected (0.0 sec)

Leave a Reply

Your email address will not be published. Required fields are marked *