Если два потока ждут блокировки, захваченные друг другом, они встают навсегда.
Почему Поток A держит блокировку 1 и ждёт блокировку 2, а поток B держит блокировку 2 и ждёт блокировку 1 → Следствие Оба встают навсегда, а за ними цепочкой встают и связанные потоки → На экране Весь сервер стоит, watchdog его перезапускает, у всех дисконнект
Основной ответственный Команда разработки · Разработка сервера
Команда разработки: задачи
Ввести правило порядка захвата блокировок, использовать блокировки с таймаутом, поставить watchdog и сохранять дамп потоков в момент зависания.
На графике
Массовый обрыв соединений · число подключений, исходящий трафик сервера
Где смотреть
Пока сервер стоит, снять стеки вызовов всех потоков. Для JVM jstack (сам находит и показывает дедлоки), для .NET dotnet-stack, для нативного сервера thread apply all bt в gdb, либо снять core-файл через gcore и разобрать его после перезапуска
Подтверждает
Два или больше потоков стоят со стеками, в которых каждый ждёт блокировку, захваченную другим, а загрузка CPU процессом всё это время близка к 0
Опровергает
Если во время зависания один поток крутится на 100% CPU, это бесконечный цикл. Если потоки ждут ответа БД или внешних сервисов, дело в синхронных вызовах или исчерпании пула потоков
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Источники
Runtime locking correctness validatorLinux kernel Если две блокировки захватываются в противоположном порядке, возникает циклическое ожидание и дедлок (lock inversion deadlock). Ядро Linux проверяет порядок захвата блокировок и предупреждает заранее
Liveness, Readiness, and Startup ProbesKubernetes Дедлок, при котором приложение работает, но не может продвинуться, ловят liveness-проверкой и перезапускают контейнер