Если две транзакции (операции БД, которые выполняются как единое целое) ждут строки, заблокированные друг другом, БД принудительно отменяет одну из них.
Почему Обмен A блокирует строки в порядке «предмет → валюта», обмен B в порядке «валюта → предмет» → Следствие БД обнаруживает дедлок и делает роллбэк одной из транзакций → На экране Обмены и крафт иногда срываются, предметы возвращаются назад
Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Инфраструктура БД
Команда разработки: задачи
Захватывать блокировки в едином порядке, делать транзакции короче, автоматически повторять при сбое.
Команда инфраструктуры: задачи
Держать обнаружение дедлоков включённым, собирать записи о дедлоках и передавать их команде разработки, на серверах MySQL с отключённым обнаружением уменьшить лимит ожидания блокировки (по умолчанию 50 секунд).
Цифры для ориентира
В MySQL (InnoDB) дедлок обнаруживается почти мгновенно, в PostgreSQL по умолчанию через 1 секунду, в SQL Server максимум примерно через 5 секунд. Всё это время оба запроса стоят. Если на сервере MySQL обнаружение отключено из-за очень большого числа одновременных запросов, ожидание длится до лимита ожидания блокировки (по умолчанию 50 секунд).
На графике
Случайные всплески · число дедлоков, число сбоев обменов
Где смотреть
В MySQL смотреть LATEST DETECTED DEADLOCK в SHOW ENGINE INNODB STATUS (только последний случай), все дедлоки в журнале ошибок при включённом innodb_print_all_deadlocks и lock_deadlocks в INFORMATION_SCHEMA.INNODB_METRICS. В PostgreSQL смотреть deadlocks в pg_stat_database, в SQL Server xml_deadlock_report в сессии system_health, включённой по умолчанию. Коды ошибок на стороне игрового сервера: MySQL 1213, PostgreSQL 40P01, SQL Server 1205
Подтверждает
В моменты сбоев обменов и крафта число дедлоков растёт, а две записанные транзакции блокируют одни и те же таблицы в противоположном порядке
Опровергает
Если число дедлоков не меняется, а сбои есть, это превышение лимита ожидания блокировки (ошибка MySQL 1205) или горячая строка (db-hot-row)
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Источники
InnoDB Startup Options and System VariablesMySQL При включённом обнаружении (по умолчанию) InnoDB сразу обнаруживает дедлок и делает роллбэк, innodb_lock_wait_timeout по умолчанию 50 секунд
Deadlock DetectionMySQL При очень высокой конкурентности само обнаружение может замедлиться, поэтому его иногда отключают и полагаются на лимит ожидания блокировки
Deadlocks guideMicrosoft SQL Server Интервал проверки на дедлок по умолчанию 5 секунд, при частых дедлоках он сокращается до 100 ms. Сессия system_health, включённая по умолчанию, собирает xml_deadlock_report, жертва получает ошибку 1205
How to Minimize and Handle DeadlocksMySQL Изменять несколько строк и таблиц всегда в одном порядке, при сбое повторять, innodb_print_all_deadlocks записывает все дедлоки
InnoDB Standard Monitor and Lock Monitor OutputMySQL LATEST DETECTED DEADLOCK: две транзакции последнего дедлока, удерживаемые и ожидаемые блокировки, транзакция, для которой сделан роллбэк