游戏卡顿白皮书 › L7 服务器操作系统(内核)
线程过多与上下文切换 Thread oversubscription, context switching
原因 ID so-context · 主责 研发团队·服务器开发 · 配合 运维团队·系统运维
在含图示和实验的完整版中打开此卡片 →
线程数远多于核心数时,操作系统光是让它们轮流运行就要耗掉大量 CPU。
起因 比如每个连接创建一个线程,线程数达到几百到几千个 → 结果 上下文切换(更换正在执行的线程)的开销和缓存未命中增加 → 画面表现 CPU 很忙但吞吐量低,tick 忽快忽慢,表现为一卡一卡、慢动作
- 症状
- 一卡一卡, 慢动作
- 因素
- 停顿, 抖动
- 谁会遇到
- 全服
- 何时出现
- 人多的时候
- 负责方
- 主责 研发团队·服务器开发 · 配合 运维团队·系统运维
- 研发团队要做的事
- 线程数与核心数匹配;使用异步 I/O(epoll、IOCP)。
- 运维团队要做的事
- 监控上下文切换次数和等待运行的线程数(vmstat 的 cs、r)。
- 数值参考
- 一次上下文切换需要几 µs,再加上之后的缓存未命中开销,代价更大。
- 监控图上
- 随人数/负载上升 · 每秒上下文切换次数、等待运行的线程数
- 查看位置
- 把 vmstat 1 的 cs(每秒上下文切换次数)、r(正在运行或等待 CPU 的数量)与核心数对比,用 pidstat -w -t 看游戏服务器各线程的自愿(cswch/s)、非自愿(nvcswch/s)上下文切换
- 确认依据
- 同时在线人数上升时 r 远超核心数,cs 也跟着飙升,非自愿上下文切换多的线程有几百个
- 排除依据
- r 保持在核心数以下则不是这个原因。只有自愿切换多,说明线程在等锁或 I/O(“锁竞争”“阻塞 I/O 模型”)
- 确认手段
- 运维工具即可确认(无需游戏代码)
出处
- Quantifying The Cost of Context Switch (ExpCS 2007) ACM
上下文切换的直接开销约 3.8 µs,加上缓存影响的间接开销为几 µs 到 1,000 µs 以上(以测量环境为准) - vmstat(8) — Linux manual page procps-ng
cs(每秒上下文切换次数)和 r(正在运行或等待运行的进程数)字段 - I/O Completion Ports Microsoft
用预先创建的线程池和 IOCP 处理大量异步 I/O,并让同时运行的线程数与 CPU 并发能力相匹配 - pidstat(1) — Linux manual page sysstat
-w 的 cswch/s 是等待资源时主动让出 CPU 的自愿上下文切换,nvcswch/s 是时间片用完后被强制切换的非自愿上下文切换;-t 按线程显示
相关原因
同一层:L7 服务器操作系统(内核)
其他层中同样导致“一卡一卡”的原因
查看含图示和实验的原卡片