한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

游戏卡顿白皮书 › L9 服务器游戏进程

死锁 Deadlock

原因 ID sp-deadlock · 主责 研发团队·服务器开发

在含图示和实验的完整版中打开此卡片 →

两个线程互相等待对方持有的锁,就会永远停住。

起因 线程 A 拿着锁 1 等锁 2,B 拿着锁 2 等锁 1 → 结果 两者都永远停住,相关线程也一个接一个停住 → 画面表现 整台服务器停住,看门狗重启服务器,所有人掉线

症状
卡住, 掉线
因素
停顿
谁会遇到
全服, 仅特定功能
何时出现
偶尔随机, 人多的时候
负责方
主责 研发团队·服务器开发
研发团队要做的事
锁顺序规则;带超时的锁;看门狗,并留下停住瞬间的线程 dump。
监控图上
连接成批断开 · 连接数、服务器发送量
查看位置
停住期间抓取所有线程的调用栈。JVM 用 jstack(会自动查找并标出死锁),.NET 用 dotnet-stack,原生服务器用 gdb 的 thread apply all bt,或者先用 gcore 生成 core 文件,重启后再分析
确认依据
两个以上的线程停在互相等待对方所持锁的调用栈上,期间进程 CPU 使用率接近 0
排除依据
停住期间有一个线程以 100% CPU 在跑,是死循环。线程们都在等 DB 或外部响应,看同步调用或线程池耗尽
确认手段
运维工具即可确认(无需游戏代码)

出处

  1. Runtime locking correctness validator Linux kernel
    以相反顺序获取两把锁,会因循环等待而死锁(lock inversion deadlock);Linux 内核会检查锁顺序并提前告警
  2. Liveness, Readiness, and Startup Probes Kubernetes
    用存活探针(liveness probe)捕捉运行中却无法推进的死锁状态,重启容器
  3. Diagnostic Tools (Java SE 21 Troubleshooting Guide) Oracle
    jstack 输出运行中 JVM 的所有线程堆栈,也会查找并标出死锁(Found one Java-level deadlock)
  4. dotnet-stack diagnostic tool - .NET CLI Microsoft
    抓取并输出 .NET 进程所有线程的托管堆栈
  5. Threads (Debugging with GDB) GNU Project
    用 thread apply all 对所有线程执行同一条命令(bt:输出调用栈)
  6. gcore(1) — Linux manual page gdb
    为运行中的程序生成 core 文件,生成后程序照常继续运行

相关原因

同一层:L9 服务器游戏进程

其他层中同样导致“卡住”的原因

查看含图示和实验的原卡片