尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux Nginx 怎么查看当前进程已使用的文件描述符数量

Linux Nginx 怎么查看当前进程已使用的文件描述符数量 前言在 Linux 上套接字、普通文件、管道、eventfd 全都用文件描述符file descriptor简称 fd来表示。Nginx 作为高并发服务器每个客户端连接、每个到上游的连接、每个打开的文件都占一个 fd所以fd 用满了是高并发场景下最典型的故障之一。症状很有辨识度错误日志里出现too many open files新连接被拒绝或者直接看到worker_connections are not enough的告警。排查这类问题光知道用了多少不够还要同时知道上限是多少、谁在占、上限是哪个层级的设置生效。因为 Linux 上 fd 上限有四层进程内的软限制、硬限制、nginx 自己的worker_rlimit_nofile、以及内核的fs.file-max任何一层卡住都会出问题。本文基于 RHEL 9 与 Ubuntu 22.04先把几个容易混淆的数字讲清楚再给出查看已用和上限的完整命令最后结合 nginx 特有的换算关系一个反向代理连接要吃两个 fd给出巡检脚本。所有命令都可以直接复制执行需要读其他用户进程时请加sudo。一、先把四个数字分清楚排查 fd 问题最常犯的错误是拿 A 层的数字和 B 层的上限比。下面这张表是基础数字查看方式层级说明进程当前已用的 fd 数/proc/PID/fd单进程该进程此刻打开的描述符数量进程的 fd 上限/proc/PID/limits或ulimit -n单进程分 soft软和 hard硬两个值系统已分配的 fd 总数fs.file-nr全局三个数字已分配、已分配但空闲、系统上限系统 fd 上限fs.file-max、fs.nr_open全局前者是全局总上限后者是单进程上限的天花板一次性看全局状态# 系统级已分配、空闲、上限 cat /proc/sys/fs/file-nr # 全局上限与单进程上限的天花板 sysctl fs.file-max fs.nr_open/proc/sys/fs/file-nr的三个数字依次是当前已分配的描述符数量、已分配但未使用的数量现代内核上通常恒为 0、系统上限。关键看第一个数字相对第三个数字的余量。需要特别强调fs.nr_open它是单进程能设置的 fd 上限的硬天花板。如果你在ulimit -Hn里想设一个比它更大的值是设不上去的。二、按进程看已用描述符/proc/PID/fd是最直接的数据源里面每个条目就是一个打开的描述符。要数总量直接数条目要分类就顺着符号链接看目标。# 1. nginx 的 master 进程 PID以发行版默认路径为准 cat /run/nginx.pid # 2. 数某个进程打开的描述符总数 ls /proc/$(cat /run/nginx.pid)/fd | wc -l # 3. 按进程逐个统计master 和所有 worker 各用了多少 for p in $(pgrep -x nginx); do printf pid%-8s fd%s\n $p $(ls /proc/$p/fd 2/dev/null | wc -l) donepgrep -x nginx按进程名精确匹配能一次列出 master 和所有 worker。注意每个 worker 的 fd 数量才是真正反映连接规模的部分master 主要持有监听套接字和日志文件数量很小。想知道这些 fd 都是什么类型可以顺着链接目标统计sudo ls -l /proc/$(cat /run/nginx.pid)/fd \ | awk {print $NF} \ | awk { if ($0 ~ /^socket:/) print socket; else if ($0 ~ /^pipe:/) print pipe; else if ($0 ~ /^anon_inode:/) print anon_inode; else print file } \ | sort | uniq -c | sort -rn反向代理场景下正常情况下socket应该占绝大多数file主要是配置、日志、证书和静态资源。如果file的数量异常增长优先排查是否有临时文件句柄没释放或者访问日志、缓存目录被大量打开。另一个常用工具是lsof它把/proc里的信息做了聚合输出更好读但需要额外安装且在 fd 数量极大时明显更慢# RHEL: sudo dnf install -y lsof Debian/Ubuntu: sudo apt install -y lsof # 某个进程打开的描述符总数 sudo lsof -p $(cat /run/nginx.pid) | wc -l # 只统计网络连接-i 网络-P 不解析端口名-n 不解析地址 sudo lsof -i -P -n | grep -c nginx如果只是想看连接数而不关心 fdss更快# 概览 ss -s # 该进程持有的已建立连接数 ss -tnp state established | grep -c nginx三、看上限ulimit、systemd 与worker_rlimit_nofile查上限时最常见的坑是查错了对象。ulimit -n只反映当前 shell 的限制它既不代表 nginx 进程的限制也不代表 systemd 服务启动时的限制。ulimit -n # 当前 shell 的软限制 ulimit -Hn # 当前 shell 的硬限制 ulimit -Sn # 软限制与 ulimit -n 等价要看 nginx 进程真正生效的上限读它自己的/proc文件# RHEL 系包安装后运行的进程名是 nginxDebian/Ubuntu 同样是 nginx grep -i Max open files /proc/$(cat /run/nginx.pid)/limits输出形如Max open files 65535 65535 files两个数字分别是软限制和硬限制。systemd 管理的服务要查 unit 而不是/etc/security/limits.conf。这是最经典的坑limits.conf由 PAM 在登录会话中应用systemd 启动的服务不经过 PAM所以你在limits.conf里给 nginx 用户写的限制对服务完全无效。# 查看 nginx.service 实际生效的 LimitNOFILE systemctl show nginx -p LimitNOFILE # 查看该值是从哪里来的unit 文件路径 systemctl cat nginx | head -20要修改就用 drop-in 覆盖不要直接改发行版自带的 unit 文件升级会被覆盖# 新建 /etc/systemd/system/nginx.service.d/limits.conf [Service] LimitNOFILE65535sudo systemctl daemon-reload sudo systemctl restart nginx systemctl show nginx -p LimitNOFILEnginx 自己还有一个覆盖层worker_rlimit_nofile。它写在 main 上下文nginx 启动时会用它给 worker 进程调用setrlimitworker_processes auto; worker_rlimit_nofile 65535;不写这个指令时worker 继承 master 的限制。如果 systemd unit 的LimitNOFILE已经调大worker_rlimit_nofile可以留空或设成相同值两者取较小值生效的是前者的话就需要对齐。四、nginx 特有的换算worker_connections与上游连接worker_connections决定单个 worker 能同时处理的连接数。做反向代理时一个客户端连接要配一个到上游的连接合起来占两个 fd所以容量预算大致是单个 worker 需要的 fd ≈ worker_connections × 2反代场景 全部 worker 需要的 fd ≈ worker_processes × worker_connections × 2也就是说worker_connections 10240配worker_processes auto假设 4 核时理论上需要约 81920 个 fd 才能跑满worker_rlimit_nofile至少要覆盖这个量级。反过来如果worker_rlimit_nofile只有 1024那worker_connections写成 10240 也没意义——超出的部分会以too many open files的形式失败。这里有个容易搞混的点worker_connections和worker_rlimit_nofile不是同一个东西前者是 nginx 内部的连接数上限后者是操作系统的进程级 fd 上限。Linux 上 nginx 会同时受这两个约束。实战一次巡检把上面几节的内容合成一个可以定期跑的巡检片段。脚本在 RHEL 9 / Ubuntu 22.04 上均可运行只读操作可以在生产直接执行。#!/bin/bash # nginx fd 巡检查看已用、上限与余量 PID$(cat /run/nginx.pid 2/dev/null || pgrep -x nginx | head -1) [ -z $PID ] { echo nginx 未运行; exit 1; } echo nginx master pid: $PID echo --- 各进程已用 fd --- for p in $(pgrep -x nginx); do printf pid%-8s fd%s\n $p $(ls /proc/$p/fd 2/dev/null | wc -l) done echo --- 进程 fd 上限 --- grep -i Max open files /proc/$PID/limits echo --- systemd 生效值 --- systemctl show nginx -p LimitNOFILE 2/dev/null || echo 非 systemd 管理 echo --- nginx 配置 --- nginx -T 2/dev/null | grep -nE ^\s*(worker_rlimit_nofile|worker_connections|worker_processes) echo --- 系统全局 --- echo file-nr: $(cat /proc/sys/fs/file-nr) sysctl fs.file-max fs.nr_open echo --- 连接概览 --- ss -s把关键几行拼成一行方便对比余量PID$(cat /run/nginx.pid) printf used%s limit%s\n \ $(ls /proc/$PID/fd | wc -l) \ $(awk /Max open files/{print $4} /proc/$PID/limits)怎么读结果各 worker 的 fd 数接近worker_rlimit_nofile或/proc/PID/limits里的软限制说明已经贴着上限跑必须调大。file-nr的第一个数字接近fs.file-max是全系统都紧张这时候要同时排查其他进程数据库、日志采集器是不是吃掉了大量 fd。nginx -T里worker_rlimit_nofile比/proc/PID/limits的软限制还大说明 systemd 层的限制才是短板worker 想调高也调不上去。各 worker 的 fd 分布很不均匀某个 worker 特别高通常是长连接分配不均可以结合ss -tnp看负载落在哪个 worker 上。常见坑点❌ 在/etc/security/limits.conf里给 nginx 用户加nofile重启服务后发现完全没生效。 ✅ systemd 启动的服务不走 PAM要用LimitNOFILE的 drop-in 覆盖文件。❌ 在 shell 里ulimit -n 65535之后重启 nginx以为生效了其实只改了当前 shell。 ✅ 改 systemd unit 的LimitNOFILE再加worker_rlimit_nofile双保险最后用/proc/PID/limits复核。❌ 把ulimit -Hn设成比fs.nr_open更大的值命令静默失败或直接报错还不知道为什么。 ✅ 先看sysctl fs.nr_open它是单进程上限的天花板。❌ 只调大worker_connections不动worker_rlimit_nofile日志里出现too many open files和worker_connections are not enough。 ✅ 两个一起调并按反代场景的× 2关系估算。❌ 用lsof -i在高并发生产机上全量扫描命令跑几分钟不返回还占满 CPU。 ✅ 优先用/proc/PID/fd和ss它们不做全表扫描lsof只在需要详细信息时限定进程使用。❌ 只看 master 进程的 fd 数量觉得很少就认为没问题。 ✅ 连接都在 worker 上必须逐个 worker 统计。❌ 直接编辑发行版自带的/usr/lib/systemd/system/nginx.servicenginx 升级后改动被覆盖限制又回到默认值。 ✅ 用/etc/systemd/system/nginx.service.d/下的 drop-in 文件。总结想查什么命令注意点某进程已用 fdls /proc/PID/fd \wc -l进程 fd 上限grep Max open files /proc/PID/limits进程实际生效值最可靠systemd 服务的限制systemctl show nginx -p LimitNOFILElimits.conf对它无效系统全局 fdcat /proc/sys/fs/file-nr对比第三个数字看余量单进程硬天花板sysctl fs.nr_open决定 hard limit 能设多大连接数ss -s、ss -tnp比lsof轻快得多正确的排查顺序是先用/proc/PID/fd数出每个 worker 的已用值再用/proc/PID/limits拿到真正生效的上限两者对比得出余量如果余量不足往上追 systemd 的LimitNOFILE、worker_rlimit_nofile和内核的fs.nr_open。最容易踩的坑集中在查错了层级——ulimit查的是 shell、limits.conf管不了 systemd 服务只有进程自己的/proc/PID/limits才是权威答案。
返回列表