Deadlock в InnoDB: диагностика и безопасный повтор транзакции

Как найти конфликтующие транзакции, проверить границы отката и настроить ограниченный повтор без повторных бизнес-действий.

Ошибка 1213 Deadlock found в InnoDB означает конфликт блокировок: транзакции ждут ресурсы друг друга, и СУБД прерывает одну из них. После такого отката приложение должно заново выполнить всю транзакцию, включая чтение данных и проверки, а не только последний UPDATE.

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

1. Отличите deadlock от долгого ожидания

Найдите в журнале приложения код драйвера, SQLSTATE, время с часовым поясом и технический идентификатор запроса. HTTP 500 сам по себе не доказывает deadlock: нужна исходная ошибка БД.

  • 1213, обычно SQLSTATE 40001: обнаружен deadlock; InnoDB откатывает выбранную транзакцию целиком.
  • 1205, Lock wait timeout: истекло ожидание блокировки. По умолчанию может откатиться только текущий SQL-оператор; поведение зависит от настройки innodb_rollback_on_timeout.
  • Обрыв соединения при COMMIT: результат может остаться неизвестным. Нельзя считать его подтверждённым откатом и запускать тот же обработчик без сверки.

Разница между откатом оператора и транзакции описана в документации MySQL. Для тайм-аута нужен отдельный обработчик с явным завершением текущей транзакции, а не продолжение частично выполненной работы.

2. Найдите обе стороны конфликта

Попросите администратора БД выполнить диагностическую команду вскоре после ошибки:

SHOW ENGINE INNODB STATUS;

В секции LATEST DETECTED DEADLOCK сопоставьте время события, участвующие транзакции, SQL, удерживаемые и ожидаемые блокировки, выбранную для отката транзакцию. Назначение этих полей приведено в справочнике MariaDB.

Это последний обнаруженный конфликт, а не история всех ошибок. Если его время не совпадает с инцидентом, вывод не подтверждает причину именно вашего сбоя. Для повторяющихся случаев администратор может временно включить innodb_print_all_deadlocks, обеспечить ротацию журнала и выключить расширенный сбор после диагностики.

Не передавайте полный вывод в публичный чат: SQL и записи блокировок могут содержать реальные значения. Для разбора оставьте структуру запросов, имена индексов, типы блокировок и порядок действий, удалив персональные данные и секреты. Связать событие с HTTP-запросом поможет поиск по request ID.

Пример: одинаковые строки, обратный порядок

Условный обработчик A сначала изменяет строку X, затем Y; обработчик B — сначала Y, затем X. Если каждый уже удерживает первую блокировку и ждёт вторую, возникает цикл ожидания.

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

3. Повторяйте транзакцию с ограничениями

Безопасный обработчик подтверждённого deadlock строится вокруг всей операции:

  1. Завершить обработку откатившейся попытки и привести соединение или объект транзакции в корректное состояние средствами драйвера либо ORM.
  2. Проверить лимит попыток и общий срок выполнения запроса.
  3. Сделать ограниченную паузу со случайным разбросом, уже не удерживая транзакцию.
  4. Начать новую транзакцию, заново прочитать данные и проверить бизнес-условия.
  5. Выполнить связанные изменения и COMMIT; сообщить об успехе только после подтверждения.
  6. При исчерпании лимита вернуть контролируемую ошибку и записать диагностическое событие.

Число попыток и задержки выбирают под допустимое время операции. Бесконечный повтор скрывает неисправность и наращивает нагрузку. Не добавляйте второй цикл, если повторами уже управляет фреймворк: сначала выясните его фактическое поведение.

Письмо, HTTP-вызов и изменение нетранзакционной таблицы не откатятся вместе с InnoDB. Если они входят в обработчик, сначала измените его границы: например, сохраняйте намерение отправки в транзакционной outbox-таблице, а доставку выполняйте отдельно с защитой от дублей. Неизвестный результат внешнего вызова разбирается по правилам повтора API после тайм-аута.

4. Уменьшите вероятность нового конфликта

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

Увеличение тайм-аута не исправляет цикл ожидания. Менять уровень изоляции или отключать обнаружение deadlock без проверки бизнес-инвариантов тоже не стоит: поведение блокировок изменится, но корректность операции сама собой не появится.

На изолированном стенде запустите конфликтующие операции параллельно. Проверьте не только отсутствие необработанной ошибки, но и итоговые данные: нет двойного изменения, потерянной записи или повторного уведомления; исчерпание лимита даёт ожидаемый отказ.

Когда нужен разбор приложения

Web-Puls помогает заметить внешнюю недоступность сайта, но HTTP-проверка не показывает блокировки InnoDB и не подтверждает корректность записи заказа. Для контроля исправления нужны журналы приложения, число откатов и повторов, длительность операций и проверка результата в БД.

Если конфликт повторяется и мешает работе сайта, отправьте заявку на диагностику: укажите затронутое действие, время, версию СУБД, код ошибки и обезличенную схему конкурирующих запросов. Формат и стоимость работ согласуются до начала; пароли и полный дамп базы в заявку не нужны.

Проверьте свой сайт прямо сейчас

Введите адрес сайта: Web-Puls покажет HTTP-код, время ответа и базовую диагностику. Для постоянного контроля можно подключить мониторинг.

Нужна помощь с диагностикой ошибки?

Опишите симптомы в короткой заявке: URL, код ответа, время появления и что менялось перед сбоем. Специалист поддержки оценит задачу и предложит формат работ.