Linux文件句柄限制调整_高并发场景说明【指导】

11次阅读

Linux 高并发服务文件句柄瓶颈需从 systemd 单元 LimitNOFILE、内核 fs.file-max、JVM 参数及进程实际 limits 四层配置,缺一不可。

Linux 文件句柄限制调整_高并发场景说明【指导】

Linux 默认的文件句柄限制(尤其是 ulimit -n)在高并发服务(如 Nginx、Redis、Java 微服务)中极易成为瓶颈,表现为连接拒绝、Too many open files 错误或请求超时。直接改 /etc/security/limits.conf 常常无效——因为 systemd 服务绕过了它。

systemd 服务的文件句柄限制必须单独配置

从 systemd 219 开始,limits.conf 对通过 systemctl start 启动的服务不再生效。必须在服务单元文件中显式设置:

  • LimitNOFILE=65536:同时控制 soft 和 hard 限制
  • 若需区分,可用 LimitNOFILE=65536:65536(soft:hard)
  • 修改后必须执行 sudo systemctl daemon-reload && sudo systemctl restart
  • 验证方式:cat /proc/$(pidof )/limits | grep "Max open files"

全局系统级限制要改 /etc/sysctl.conf 而非仅 ulimit

用户级 ulimit -n 只影响当前 shell 及其子进程;真正决定内核能管理多少文件描述符的是 fs.file-max

  • 查看当前值:cat /proc/sys/fs/file-max
  • 临时调整:sudo sysctl -w fs.file-max=2097152
  • 永久生效:在 /etc/sysctl.conf 中添加 fs.file-max = 2097152
  • 注意:该值建议设为单机最大预期连接数 × 1.5~2 倍,避免被内核强制回收 socket
fs.file-max = 2097152 fs.nr_open = 2097152

Java 应用常因 JVM 忽略系统限制而失败

JVM 启动时若未显式传参,会继承启动用户的 ulimit,但某些 JDK 版本(尤其 OpenJDK 11+)在容器或 systemd 下可能读取不到正确值:

  • 强制指定:在 JVM 启动参数中加 -XX:+UseG1GC -XX:MaxOpenFiles=65536(JDK 12+ 支持,旧版无效)
  • 更通用做法:确保 systemd 单元中已设 LimitNOFILE,并用 java -XX:+PrintFlagsFinal -version | grep MaxOpenFiles 确认是否识别
  • Spring Boot 应用还需检查 server.tomcat.max-connectionsserver.tomcat.accept-count,避免线程池耗尽前就卡在文件句柄上

排查时别只看 ulimit -n,要查进程实际 limits

很多问题表面是“句柄不够”,实则是某个进程(比如 supervisord、dockerd 或 sshd)占用了大量句柄却没释放:

  • 快速统计:lsof -nPi | awk '{print $2}' | sort | uniq -c | sort -nr | head -10
  • 查某进程所有句柄:lsof -p | wc -l
  • 注意:Docker 容器默认继承宿主机 fs.file-max,但每个容器的 ulimit 需单独用 --ulimit nofile=65536:65536 指定

最常被忽略的是:systemd 的 DefaultLimitNOFILE 设置(在 /etc/systemd/system.conf)会影响所有未显式覆盖的服务,但它不会自动下发到已启用的服务,必须 reload + restart 才生效。

text=ZqhQzanResources