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

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

线程池耗尽 Thread pool starvation

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

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

处理任务的工作线程全被慢操作占住时,新请求只能干等。

起因 工作线程都在等外部 API、DB 响应,被占住 → 结果 新请求没有线程可分配 → 画面表现 登录、商城等特定功能无限加载

症状
连不上/无限加载, 操作延迟, 卡住
因素
停顿
谁会遇到
仅特定功能, 全服
何时出现
人多的时候, 刚登录/维护结束后
负责方
主责 研发团队·服务器开发
研发团队要做的事
给慢调用设超时;按功能拆分线程池;改为异步。
监控图上
触顶后走平 · 线程池线程数、队列长度,请求处理时间
查看位置
.NET 用 dotnet-counters monitor 看线程池线程数和队列长度(.NET 9 及以后为 dotnet.thread_pool.thread.count、dotnet.thread_pool.queue.length,8 及以前为 ThreadPool Thread Count、ThreadPool Queue Length),用 dotnet-stack 确认工作线程在哪里等待。JVM、原生服务器用线程 dump 确认同样的内容
确认依据
CPU 使用率远低于 100%,线程数却持续缓慢增加或顶在上限,队列堆积,大部分工作线程在等同一个外部调用(DB、HTTP)的响应
排除依据
队列是空的仍然慢,说明被调用方本身慢,看“级联故障”或“依赖外部服务”
确认手段
运维工具即可确认(无需游戏代码)
深入了解
如果接收数据包和游戏逻辑共用同一个工作线程池,几个慢操作占满所有工作线程的那一刻,整台服务器的数据包处理都会停住。
真实案例
Riot Games 2021: League of Legends EUW 5 小时故障:一个辅助 DB 导致全服停摆

出处

  1. Debug ThreadPool Starvation Microsoft
    池里没有剩余线程、新任务排队时响应会变慢,原因是占住线程的阻塞代码。在 dotnet-counters 中,CPU 远低于 100% 而 dotnet.thread_pool.thread.count 持续缓慢增加,就是耗尽的信号(dotnet.thread_pool.queue.length 往往也很大);用 dotnet-stack 确认线程在哪里等待
  2. Avoiding insurmountable queue backlogs AWS
    并发处理数 = 到达率 × 延迟(利特尔法则)。每秒 100 个请求时,延迟从 100 ms 增至 10 秒,线程就从 10 个增至 1,000 个,线程池耗尽
  3. Bulkhead Pattern Microsoft Azure
    每个被调用方单独设连接池、线程池,一个被调用方故障只会堵住它自己的池
  4. .NET runtime metrics .NET
    dotnet.thread_pool.thread.count(线程池线程数)、dotnet.thread_pool.queue.length(排队的任务数)从 .NET 9 起提供
  5. Well-known EventCounters in .NET Microsoft
    .NET 8 及以前的 ThreadPool Thread Count(threadpool-thread-count)、ThreadPool Queue Length(threadpool-queue-length)

相关原因

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

其他层中同样导致“连不上/无限加载”的原因

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