Кейс: дедлок в Postgres из-за разного порядка блокировок строк
Два сервиса обновляли заказ и остаток на складе в одной транзакции, но в разном порядке. Один код сначала блокировал строку заказа, потом строку товара. Другой — сначала товар, потом заказ. При параллельных запросах транзакции время от времени схлопывались в deadlock.
Postgres такие ситуации находит сам: детектор дедлоков ждёт deadlock_timeout (по умолчанию 1 секунда), потом откатывает одну из транзакций с ошибкой deadlock detected. Проблема не в базе — она честно ловит взаимную блокировку. Проблема в коде, который блокирует строки в непредсказуемом порядке.
Фикс — договориться о едином порядке блокировки во всех местах: например, всегда сначала SELECT ... FOR UPDATE по возрастанию id, независимо от бизнес-логики метода.
Спросят, почему не поставить SELECT ... FOR UPDATE NOWAIT везде, чтобы упасть сразу вместо ожидания deadlock_timeout. Это меняет модель поведения на fail-fast — код должен уметь ретраить транзакцию, а не просто отдавать пользователю ошибку блокировки.
Единый порядок блокировки строк — это соглашение на уровне всей кодовой базы, а не одного сервиса.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки
· 21.08
классика, сам так ловил. а сколько времени ушло именно на воспроизведение и поиск порядка блокировок? фикс-то копеечный, а вот детект в проде обычно жрёт дни
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён