1. 故障现象
- 场景:最近上线了一个包含 JS 反爬(Cookie 验证)的新版本。
- 症状:发版后服务器频繁“挂掉”,表现为 SSH 无法登录、网站无法访问(Nginx 502/503 或直接超时)。
- 诡异点:监控显示服务器的 CPU 和内存负载并不高,通过控制台强制重启后恢复,但过一段时间又复现。
- 配置:服务器为 2核 4G 规格。
2. 排查过程
第一步:常规诊断
使用 top、free 查看资源,发现 CPU 仅 10%,内存剩余也充足。并没有发生内存溢出(OOM)或 CPU 跑满的情况。
第二步:日志分析
检查 /var/log/syslog 和 dmesg,发现了关键报错:
Jan 28 00:00:02 ip-xxx logrotate[129511]: error: unable to open …: Too many open files in system
同时,Nginx 的 error.log 中出现大量:
connect() failed (111: Unknown error) while connecting to upstream
注意:这里的 Too many open files in system 是指整个系统的文件打开数达到了上限,而不是某个进程达到了上限。
第三步:检查配置
执行 sysctl fs.file-max 查看系统级限制:
$ cat /proc/sys/fs/file-nr
5120 0 5120
惊人发现:系统全局允许打开的最大文件句柄数(fs.file-max)竟然被设置成了 5120。
对于一台运行了 MySQL、Nginx、Go应用以及各种监控组件(如阿里云盾)的服务器来说,5120 简直是“杯水车薪”。仅 MySQL 和阿里云盾通常就能消耗掉 4000+ 个句柄。
3. 根因分析:为何发版 JS 反爬后才炸?
为什么之前没事,发了 JS 反爬版就挂了?这就涉及到了 “连接放大效应”。
- 用户请求 -> 返回 JS 验证页。
- 浏览器执行 JS -> 写入 Cookie -> 自动刷新页面。
- 服务器验证 Cookie -> 返回真页面。
- 短时间内建立和断开大量 TCP 连接,会产生大量处于 TIME_WAIT 状态的 socket。
- 在 Linux 中,socket 也占用文件描述符。
- 系统本身已占用约 4500 个句柄(MySQL + 云盾等)。
- 剩余可用句柄仅几百个。
- JS 反爬带来的流量翻倍和 TIME_WAIT 瞬间吃光了这几百个剩余配额。
- 结果:系统无法建立新连接,无法写日志,SSH 甚至无法 fork 新进程(因为需要打开库文件),服务器彻底“假死”。
4. 误区澄清
“我之前配置过 65536,为什么不生效?”
这是一个非常经典的 Linux 运维误区。Linux 有两层文件描述符限制:
进程级/用户级限制 (ulimit -n / /etc/security/limits.conf):
- 限制单个用户或单个进程能打开多少文件。
- 你配置的 65536 生效了,但它受限于系统的总上限。
- 比喻:银行限制你此卡单日限额 6万。
系统级总限制 (fs.file-max / /etc/sysctl.conf):
- 限制整个操作系统内核所有进程加起来能打开多少文件。
- 我们遇到的问题是这个值被设为了 5120。
- 比喻:银行金库里总共只有 5000 块钱。
结论:当金库(系统总上限)没钱时,你的卡限额(进程限制)再高也取不出钱来。
5. 解决方案
修改系统内核参数,大幅提升总上限。对于 4G 内存的服务器,100万是安全的。
# 1. 修改配置文件
echo "fs.file-max = 1000000" | sudo tee -a /etc/sysctl.conf
# 2. 立即生效
sudo sysctl -p
# 3. 验证
cat /proc/sys/fs/file-nr
网硕互联帮助中心





评论前必须登录!
注册