磁盘还有空间,程序却报 Too many open files;df -h 正常但 df -i 爆红——这两个是 Linux 上最隐蔽的资源耗尽问题。这篇讲它们的成因、定位和根治,命令全部可抄。
需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。
一、文件描述符(fd)是什么
Linux 里「一切皆文件」:打开一个普通文件、建立一个网络连接、一个 socket,都消耗一个文件描述符。默认上限很低:
# 系统级上限
cat /proc/sys/fs/file-max
# 当前 shell 的软/硬限制
ulimit -n
# 默认常见 1024——高并发服务轻易撞墙撞墙时的报错家族:
Too many open files ← 程序打开文件/连接失败
socket: too many open files ← 新连接建不了
nginx: accept() failed (24: Too many open files)
java.io.IOException: Too many open files为什么危险:游戏服、Nginx、MySQL、Redis 这类高连接服务,每个玩家连接就是一个 fd。默认 1024,同时在线几百人就崩。
二、定位:谁在狂吃 fd
# 1. 全系统 fd 用量
cat /proc/sys/fs/file-nr # 已分配 / 空闲 / 最大
# 2. 按进程排序,谁占最多
ls /proc/*/fd 2>/dev/null | wc -l # 粗略
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
n=$(ls /proc/$pid/fd 2>/dev/null | wc -l)
[ "$n" -gt 100 ] && echo "$n $pid $(cat /proc/$pid/comm 2>/dev/null)"
done | sort -rn | head
# 3. 看具体是什么 fd(连接?文件?)
ls -l /proc/<PID>/fd | head -30
# 4. 连接数统计(游戏服/网关重点)
ss -s # 总览
ss -tn | wc -l # 当前 TCP 连接数
ss -tn state established | wc -l典型场景:
| 现象 | 原因 |
|---|---|
| 某服务 fd 几千且持续涨 | fd 泄漏:连接关了没释放 |
| Nginx fd = 连接数×2+ | 正常,但上限要跟上 |
| 游戏服 fd 随玩家数涨 | 正常,按人数上限配 |
| fd 涨到几万不降 | 程序 bug,找开发者或升级 |
三、根治:调高上限
3.1 systemd 服务(重点)
systemd 的服务不读 /etc/security/limits.conf,这是最常见的「改了没生效」:
# 正确做法:服务单元里配
sudo systemctl edit nginx
# 加:
[Service]
LimitNOFILE=65535
sudo systemctl daemon-reload
sudo systemctl restart nginx
# 验证(看进程的实际限制)
cat /proc/$(pidof nginx | cut -d' ' -f1)/limits | grep "open files"3.2 系统全局
# /etc/security/limits.conf(对登录 shell 生效)
* soft nofile 65535
* hard nofile 65535
# 系统级上限
echo "fs.file-max = 2097152" | sudo tee /etc/sysctl.d/99-fd.conf
sudo sysctl -p /etc/sysctl.d/99-fd.conf3.3 配多少合适
| 场景 | 建议值 |
|---|---|
| 个人小站 | 65535 |
| 游戏服(每连接 1~2 fd) | 玩家上限 ×4,如 32 人服给 65535 足够 |
| 高并发网关/代理 | 100000+ |
| 数据库 | 按 max_connections×3 估算 |
调高只是「不撞墙」,泄漏还得靠修——fd 只涨不降的服务,早晚把 10 万也吃完。
四、inode 耗尽:另一种满
inode 是文件的「元数据」(属性、位置),每个文件占一个 inode。磁盘按 inode 数分配,小文件海量时 inode 先耗尽:
# 看 inode 使用率
df -ih
# 输出示例:
# 文件系统 Inode 已用(I) 可用(I) 已用% 挂载点
# /dev/vda1 1.2M 480K 720K 40% /df -h 显示还有 40G,但 df -i 100%——新建文件报 No space left on device,误以为磁盘满。
定位小文件海:
# 哪个目录文件数最多(按 inode)
for d in /var /tmp /home /opt; do
echo "$d: $(find $d -xdev 2>/dev/null | wc -l)"
done
# 深入找
find /var/spool/postfix -xdev 2>/dev/null | wc -l # 邮件队列常见
find /var/lib/mysql -xdev 2>/dev/null | wc -l # 表碎片
find /tmp -xdev 2>/dev/null | wc -l # 会话/临时文件常见元凶与清理:
| 位置 | 为什么爆 | 清理 |
|---|---|---|
/var/spool/postfix | 退信/队列堆积 | postsuper -d ALL |
/tmp、/var/tmp | 会话文件、上传残留 | 删 7 天前的 |
| PHP session 目录 | 会话文件没清理 | session.gc_maxlifetime + 定时清 |
| 邮件目录 | 用户邮件多 | 归档/删除 |
| 小文件备份 | 按文件备份的海量小文件 | 打包成 tar 再存 |
# 批量清 /tmp 7 天前(系统自动的 tmpfiles 也管这)
find /tmp -type f -mtime +7 -delete
find /tmp -type d -empty -mtime +7 -deleteinode 不能「扩容」——ext4 格式化时 inode 比例固定,满了只能删文件或重新格式化(分配更多 inode)。所以从源头控制小文件数量才是正解:日志归 logrotate、会话设过期、备份打 tar 包,见磁盘空间排查与清理实战。
五、监控:两个指标都要看
# 每日巡检加上这两行
df -h | grep -v tmpfs # 空间
df -i | grep -v tmpfs # inode
cat /proc/sys/fs/file-nr # fd# 告警 cron(空间或 inode 超 80%)
0 9 * * * df -h / | awk 'NR==2 && $5+0>80 {print "磁盘空间:"$0}'; df -i / | awk 'NR==2 && $5+0>80 {print "inode:"$0}' | mail -s "资源告警" admin@example.com接入监控系统见Prometheus 监控体系,告警规则模板见服务器日常巡检清单与自动化。
六、速查表
| 症状 | 命令 | 解法 | |
|---|---|---|---|
| Too many open files | cat /proc/sys/fs/file-nr、`ls /proc/PID/fd \ | wc -l` | 服务配 LimitNOFILE;查 fd 泄漏 |
| No space left 但 df -h 有空 | df -i | 清小文件(postfix/tmp/session) | |
| 连接建立失败 | ss -s、ulimit -n | 调 nofile + 查连接泄漏 | |
| 改了 limits.conf 不生效 | cat /proc/PID/limits | systemd 服务要在单元里配 |
文件描述符和 inode 是 Linux 的两条暗线:平时无感,耗尽时业务猝死。记住三个命令(df -i、cat /proc/sys/fs/file-nr、ls /proc/PID/fd)、两个配置(LimitNOFILE、logrotate),这两类故障就尽在掌握。
需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。延伸阅读:磁盘空间排查与清理实战、僵尸进程与 CPU 异常排查、内存泄漏排查实战。
延伸阅读
- 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
- 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
- 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
- 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
- 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
- RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
- 短链接服务搭建:Shlink 自托管,链接数据自己掌握
- 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道

[...]netsh advfirewall firewall add rule name="GameRange" dir=in action=allow protocol=UDP localport=26901-26903完整的 Windows 环境准备(远程桌面连接、运行库安装、SteamCMD 用法、开机自启、8 个常见坑)见:《Windows 云服务器开服通用前置教程》→ htt[...]
2026-10-18 回复