核心内容摘要
铜铜铜铜铜铜铜铜好大好深色
故障现象场景最近上线了一个包含 JS 反爬Cookie 验证的新版本。
症状发版后服务器频繁“挂掉”表现为 SSH 无法登录、网站无法访问Nginx 502/503 或直接超时。
诡异点监控显示服务器的 CPU 和内存负载并不高通过控制台强制重启后恢复但过一段时间又复现。
配置服务器为 2核 4G 规格。
排查过程第一步常规诊断使用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-nr512005120惊人发现系统全局允许打开的最大文件句柄数fs.file-max竟然被设置成了5120。
对于一台运行了 MySQL、Nginx、Go应用以及各种监控组件如阿里云盾的服务器来说5120 简直是“杯水车薪”。
仅 MySQL 和阿里云盾通常就能消耗掉 4000 个句柄。
根因分析为何发版 JS 反爬后才炸为什么之前没事发了 JS 反爬版就挂了这就涉及到了“连接放大效应”。
旧版本用户请求 - 返回页面。
消耗 1 个 TCP 连接。
新版本JS反爬用户请求 - 返回 JS 验证页。
浏览器执行 JS - 写入 Cookie -自动刷新页面。
服务器验证 Cookie - 返回真页面。
流量翻倍这种机制强迫每个真实用户至少发起2次请求。
TIME_WAIT 堆积短时间内建立和断开大量 TCP 连接会产生大量处于TIME_WAIT状态的 socket。
在 Linux 中socket 也占用文件描述符。
击穿水位系统本身已占用约 4500 个句柄MySQL 云盾等。
剩余可用句柄仅几百个。
JS 反爬带来的流量翻倍和 TIME_WAIT 瞬间吃光了这几百个剩余配额。
结果系统无法建立新连接无法写日志SSH 甚至无法 fork 新进程因为需要打开库文件服务器彻底“假死”。
误区澄清“我之前配置过 65536为什么不生效”这是一个非常经典的 Linux 运维误区。
Linux 有两层文件描述符限制进程级/用户级限制 (ulimit -n//etc/security/limits.conf)限制单个用户或单个进程能打开多少文件。
你配置的 65536 生效了但它受限于系统的总上限。
比喻银行限制你此卡单日限额 6万。
系统级总限制 (fs.file-max//etc/sysctl.conf)限制整个操作系统内核所有进程加起来能打开多少文件。
我们遇到的问题是这个值被设为了 5120。
比喻银行金库里总共只有 5000 块钱。
结论当金库系统总上限没钱时你的卡限额进程限制再高也取不出钱来。
解决方案修改系统内核参数大幅提升总上限。
对于 4G 内存的服务器100万是安全的。
#
修改配置文件echofs.file-max 1000000|sudotee-a /etc/sysctl.conf#
立即生效sudosysctl -p#
验证cat/proc/sys/fs/file-nr
避坑指南系统初始化检查新服务器到手务必检查fs.file-max。
不要只看ulimit -n。
反爬系统的代价引入 JS 验证、重定向等机制会成倍增加连接数和并发压力评估容量时需要考虑到这一点特别是 TIME_WAIT 的影响。
监控盲区CPU 和内存低不代表服务器健康文件描述符FD使用率是一个关键但常被忽视的监控指标。