Deadlocks на собеседовании системного аналитика

Готовься к собесу аналитика как в Duolingo
10 минут в день — SQL, Python, A/B, метрики. 1700+ вопросов в Telegram
Открыть Карьерник в Telegram

Карьерник — Duolingo для аналитиков: 10 минут в день тренируй SQL, Python, A/B, статистику, метрики и ещё 3 темы собеса. 1500+ вопросов в Telegram-боте. Бесплатно.

Зачем спрашивают на собесе SA

Deadlocks — частая production проблема. SA должен закладывать защиту в дизайн. На собесе SA: «как возникает deadlock», «как избежать».

Что такое deadlock

Две / больше транзакций ждут друг друга, никто не может продвинуться.

T1: захватил row A, пытается row B
T2: захватил row B, пытается row A

→ Deadlock. Никто не закончится.

В БД: транзакция блокирует строку (UPDATE / SELECT FOR UPDATE), пока не закоммитит.

Условия Coffman

Для deadlock необходимы все 4:

  1. Mutual exclusion. Ресурс не может shared (только один владелец).
  2. Hold and wait. Транзакция держит ресурс и ждёт другой.
  3. No preemption. Нельзя забрать ресурс силой (только владелец release'ит).
  4. Circular wait. Замкнутый цикл ожидания.

Убрать любое условие — нет deadlock.

Detection vs prevention

Detection. БД мониторит граф ожидания. При обнаружении цикла — kill одну транзакцию (deadlock victim), возвращает ошибку.

PostgreSQL: ERROR: deadlock detected
MySQL InnoDB: ERROR 1213: Deadlock found
Oracle: ORA-00060

Application должен handle: retry transaction.

Prevention. Архитектурно избежать.

  • Lock ordering. Все транзакции захватывают locks в одном порядке.
  • Timeouts. Ждать только N секунд, потом abort.
  • Optimistic locking. Не lock'ать, а проверять version при commit. Конфликт → retry.

Большинство БД — detection (кому нужен, тот retry'ит).

Готовься к собесу аналитика как в Duolingo
10 минут в день — SQL, Python, A/B, метрики. 1700+ вопросов в Telegram
Открыть Карьерник в Telegram

Lock ordering

Главное правило для prevention:

# плохо
T1: lock(A); ...; lock(B);
T2: lock(B); ...; lock(A);  # обратный порядок → deadlock

# хорошо
def transfer(a, b, amount):
    first, second = sorted([a, b])  # детерминированный порядок
    lock(first); lock(second)
    a.balance -= amount
    b.balance += amount

Все транзакции lock'ат в order.

Deadlock в распределённых системах

В микросервисах локальный БД-deadlock не покрывает все случаи.

Distributed deadlock. Два сервиса делают синхронные RPC друг к другу с blocking ресурсов.

Service A holds resource X, calls B
Service B holds resource Y, calls A
→ Distributed deadlock

Detection распределённо сложно.

Решение. Async messaging вместо sync RPC. Saga вместо distributed transactions.

Частые ошибки

Application не handle deadlock errors. На kill victim — ошибка наружу. Должен быть retry с backoff.

Long-running транзакции. Дольше держат locks → больше шанс deadlock. Дробить.

Случайный порядок locks. Code в разных местах захватывает inconsistently. Convention обязательна.

Игнорировать timeouts. Без timeout транзакция зависает forever, если detection не сработала.

Optimistic locking без version check. В производственных update'ах — race condition.

Связанные темы

FAQ

Можно ли deadlock в Postgres MVCC?

Да. Read-only запросы не блокируют (snapshot isolation), но UPDATE / SELECT FOR UPDATE — да.

Это официальная информация?

Нет. Статья основана на классике (Coffman 1971), документации Postgres / MySQL / Oracle.


Тренируйте системный анализ — откройте тренажёр с 1500+ вопросами для собесов.