游戏卡顿白皮书 › L12 数据库
DB 死锁 Database deadlock
原因 ID db-deadlock · 主责 研发团队·服务器开发 · 配合 运维团队·数据库运维
在含图示和实验的完整版中打开此卡片 →
两个事务(作为一个整体处理的一组 DB 操作)互相等待对方锁住的行时,DB 会强制取消其中一个。
起因 交易 A 按物品→货币的顺序加锁,B 按货币→物品的顺序加锁 → 结果 DB 检测到死锁,回滚其中一方 → 画面表现 交易、制作偶尔失败,物品回退
- 症状
- 吞操作/回档, 操作延迟
- 因素
- 丢包, 停顿
- 谁会遇到
- 仅特定功能
- 何时出现
- 人多的时候, 做特定操作时
- 负责方
- 主责 研发团队·服务器开发 · 配合 运维团队·数据库运维
- 研发团队要做的事
- 统一加锁顺序,缩短事务,失败时自动重试。
- 运维团队要做的事
- 保持死锁检测开启,收集死锁记录并共享;关闭了检测的 MySQL 服务器要调低锁等待超时(默认 50 秒)。
- 数值参考
- 检测所需时间:MySQL(InnoDB)几乎即时,PostgreSQL 默认 1 秒,SQL Server 最多约 5 秒。在此期间两个请求都停在原地。如果服务器因并发请求极多而关闭了 MySQL 的死锁检测,就要一直等到锁等待超时(默认 50 秒)。
- 监控图上
- 偶发随机尖峰 · 死锁次数、交易失败次数
- 查看位置
- MySQL 看 SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK(最近 1 次),开启 innodb_print_all_deadlocks 后写入错误日志的所有死锁,以及 INFORMATION_SCHEMA.INNODB_METRICS 的 lock_deadlocks。PostgreSQL 看 pg_stat_database 的 deadlocks,SQL Server 看默认开启的 system_health 会话中的 xml_deadlock_report。游戏服务器侧的错误码为 MySQL 1213、PostgreSQL 40P01、SQL Server 1205
- 确认依据
- 交易、制作失败的时刻死锁次数增加,记录下的两个事务以相反的顺序锁同一组表
- 排除依据
- 死锁次数不变却失败,看锁等待超时(MySQL 错误 1205)或“热点行锁竞争”(db-hot-row)
- 确认手段
- 运维工具即可确认(无需游戏代码)
出处
- InnoDB Startup Options and System Variables MySQL
开启检测时(默认),InnoDB 会立即检测到死锁并回滚;innodb_lock_wait_timeout 默认 50 秒 - Deadlock Detection MySQL
并发极高时检测本身可能变慢,有时会关闭检测,交给锁等待超时处理 - Lock Management (PostgreSQL Documentation) PostgreSQL
deadlock_timeout 默认 1 秒:锁等待达到这个时长后才做死锁检查 - Deadlocks guide Microsoft SQL Server
死锁检查默认间隔 5 秒,死锁频繁时缩短到 100 ms;默认开启的 system_health 会话收集 xml_deadlock_report;被牺牲的一方收到错误 1205 - How to Minimize and Handle Deadlocks MySQL
多行、多表始终按相同顺序修改,失败就重试,用 innodb_print_all_deadlocks 记录所有死锁 - InnoDB Standard Monitor and Lock Monitor Output MySQL
LATEST DETECTED DEADLOCK:最近一次死锁的两个事务、各自持有和等待的锁,以及被回滚的一方 - InnoDB INFORMATION_SCHEMA Metrics Table MySQL
INNODB_METRICS 的 lock_deadlocks 计数器(默认启用) - Server Error Message Reference MySQL
1213 ER_LOCK_DEADLOCK(死锁),1205 ER_LOCK_WAIT_TIMEOUT(锁等待超时) - The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
pg_stat_database 的 deadlocks:该数据库中检测到的死锁次数 - PostgreSQL Error Codes (PostgreSQL Documentation) PostgreSQL
40P01 deadlock_detected
相关原因
同一层:L12 数据库
其他层中同样导致“吞操作/回档”的原因
查看含图示和实验的原卡片