15 10 月 2026

磁盘还有空间,程序却报 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.conf

3.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 -delete

inode 不能「扩容」——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 filescat /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/limitssystemd 服务要在单元里配

文件描述符和 inode 是 Linux 的两条暗线:平时无感,耗尽时业务猝死。记住三个命令(df -i、cat /proc/sys/fs/file-nr、ls /proc/PID/fd)、两个配置(LimitNOFILE、logrotate),这两类故障就尽在掌握。

需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。延伸阅读:磁盘空间排查与清理实战、僵尸进程与 CPU 异常排查、内存泄漏排查实战。

延伸阅读
  1. 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
  2. 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
  3. 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
  4. 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
  5. 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
  6. RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
  7. 短链接服务搭建:Shlink 自托管,链接数据自己掌握
  8. 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道
更多阅读
  1. 上一篇:内存泄漏排查实战:从确认泄漏到定位代码到工程化兜底
  2. 下一篇:MySQL 慢查询优化实战:慢日志、EXPLAIN、索引三板斧
发表评论 1

取消回复