游戏卡顿白皮书 › L7 服务器操作系统(内核)
文件描述符上限 File descriptor limit (ulimit)
原因 ID so-fd · 主责 运维团队·系统运维 · 配合 研发团队·服务器开发
在含图示和实验的完整版中打开此卡片 →
每个连接都要占用一个文件描述符(fd,操作系统给打开的文件、socket 分配的编号),而一个进程能打开的 fd 数量是有限的。
起因 同时在线人数达到进程的文件描述符上限 → 结果 服务器无法接受新连接(Too many open files),打开日志、建立 DB 连接也一起失败 → 画面表现 从某个固定人数开始谁都进不来,表现为连不上/无限加载
- 症状
- 连不上/无限加载
- 因素
- 丢包
- 谁会遇到
- 全服
- 何时出现
- 刚登录/维护结束后, 人多的时候
- 负责方
- 主责 运维团队·系统运维 · 配合 研发团队·服务器开发
- 研发团队要做的事
- 结束连接时务必关闭 socket(防止 fd 泄漏);accept 因 EMFILE(fd 不足)失败时,先暂停接受连接一会儿,或用预先留出的备用 fd 接下连接后立即关闭(以免反复处理同一个连接通知、白白消耗 CPU)。
- 运维团队要做的事
- 检查 ulimit 和服务配置(systemd 的 LimitNOFILE);接近上限时告警。
- 数值参考
- Linux 在不单独配置服务的情况下,上限仍常常是 1,024。游戏服务器通常会调到数万到数十万。Windows 没有这么低的默认上限。
- 监控图上
- 触顶后走平 · 进程打开的 fd 数、同时在线人数
- 查看位置
- 用 pidstat -v 看游戏服务器进程的 fd-nr(打开的文件描述符数),用 /proc/PID/limits 看打开文件数上限,在服务器日志里找 accept 失败(EMFILE、Too many open files)
- 确认依据
- fd 数在上限值处走平,从那一刻起 accept 以 EMFILE 失败
- 排除依据
- fd 数离上限还很远则不是这个原因。连接请求在内核被丢弃,看“连接队列(backlog)溢出”;问题在连接跟踪,看“服务器 conntrack 表耗尽”
- 确认手段
- 运维工具即可确认(无需游戏代码)
- 深入了解
- 没被接受的连接仍留在内核连接队列(backlog)里。视服务器代码而定,进程可能会不断收到“有新连接”的通知,白白浪费 CPU。
出处
- systemd-system.conf(5) — Linux manual page systemd
服务的 DefaultLimitNOFILE 默认值为 1024:524288(软上限 1,024) - accept(2) — Linux manual page Linux man-pages
达到进程的 fd 上限时,accept 以 EMFILE 失败 - Maximum Number of Sockets Supported Microsoft
Windows Winsock 只按可用内存限制 socket 数量 - pidstat(1) — Linux manual page sysstat
-v 的 fd-nr:进程打开的文件描述符数 - proc_pid_limits(5) — Linux manual page Linux man-pages
/proc/PID/limits 里有进程各项资源上限的软、硬值
相关原因
同一层:L7 服务器操作系统(内核)
其他层中同样导致“连不上/无限加载”的原因
查看含图示和实验的原卡片