文件打开数

文件打开数

概述

Linux 系统对进程可打开的文件描述符数量有限制,当服务需要处理大量并发连接(如 Nginx、数据库、消息队列)时,默认限制可能成为性能瓶颈。本文档涵盖文件打开数限制的查看、临时修改和永久配置方法。

适用场景

  • 高并发 Web 服务器(Nginx、Tomcat)
  • 数据库服务(MySQL、PostgreSQL、Redis)
  • 消息队列(Kafka、RabbitMQ)
  • 容器化部署环境

查看当前限制

查看系统级限制

# 查看系统最大文件打开数
cat /proc/sys/fs/file-max

# 查看系统已使用的文件描述符数量
cat /proc/sys/fs/file-nr
# 输出三个数字:已分配文件句柄数 | 已使用文件句柄数 | 文件句柄最大值

查看用户级限制

# 查看当前会话的软限制(当前生效值)
ulimit -n

# 查看当前会话的硬限制(最大值)
ulimit -Hn

查看特定进程的限制

# 查看指定进程的文件打开限制
cat /proc/<PID>/limits | grep "Max open files"

# 查看指定进程已打开的文件数
lsof -p <PID> | wc -l

查看系统总体使用情况

# 查看系统所有进程打开的文件数
lsof | wc -l

# 查看进程打开文件数排序(Top 10)
lsof 2>/dev/null | awk '{print $2}' | sort | uniq -c | sort -rn | head -10

修改文件打开数

临时修改(重启失效)

# 修改当前会话的用户级限制
ulimit -n 65536

# 修改系统级限制(立即生效)
echo 1048576 > /proc/sys/fs/file-max

永久修改

1. 修改系统级配置(/etc/sysctl.conf)

# 编辑系统配置文件
sudo vi /etc/sysctl.conf

# 添加或修改以下参数
fs.file-max = 1048576
fs.nr_open = 1048576

# 使配置立即生效
sudo sysctl -p

2. 修改用户级限制(/etc/security/limits.conf)

sudo vi /etc/security/limits.conf

# 针对所有用户
* soft nofile 65536
* hard nofile 131072

# 针对特定用户
username soft nofile 65536
username hard nofile 131072

# 针对 root 用户
root soft nofile 65536
root hard nofile 131072

说明

  • soft 软限制:当前生效值,不能超过硬限制
  • hard 硬限制:最大值,需要 root 权限修改
  • 修改后需重新登录生效

3. 修改 PAM 模块配置(可选)

部分系统还需修改 PAM 配置使 limits.conf 生效:

# CentOS/Rocky
sudo vi /etc/pam.d/login
# 添加以下行(通常已存在)
session required pam_limits.so

4. 修改 systemd 服务配置

重要:CentOS 7 / Rocky 9 中,systemd 管理的服务(如 Nginx、MySQL、Docker)不受 limits.conf 影响,需单独配置。

# 方式A:修改全局 systemd 配置
sudo vi /etc/systemd/system.conf
# 取消注释并修改
DefaultLimitNOFILE=65536
DefaultLimitNPROC=65536

# 方式B:针对特定服务修改
sudo vi /usr/lib/systemd/system/<service-name>.service
# 在 [Service] 部分添加
LimitNOFILE=65536
LimitNPROC=65536

# 重新加载 systemd 配置
sudo systemctl daemon-reload
sudo systemctl restart <service-name>

5. Docker 容器配置

# 方式A:在 docker-compose.yaml 中配置
services:
  app:
    image: nginx
    ulimits:
      nofile:
        soft: 65536
        hard: 131072

# 方式B:在 Dockerfile 中配置
RUN ulimit -n 65536

# 方式C:运行容器时指定
docker run --ulimit nofile=65536:131072 -d nginx

验证修改结果

# 1. 验证系统级限制
cat /proc/sys/fs/file-max

# 2. 验证用户级限制(需重新登录后验证)
ulimit -n
ulimit -Hn

# 3. 验证当前进程的限制
cat /proc/self/limits | grep "Max open files"

# 4. 验证特定服务进程的限制
sudo systemctl show <service-name> | grep LimitNOFILE

# 5. 验证 Docker 容器限制
docker exec <container-name> ulimit -n

各场景配置速查表

场景 配置方式 生效方式
系统全局(所有用户) /etc/sysctl.conf(fs.file-max) sysctl -p
用户登录会话 /etc/security/limits.conf 重新登录
SSH 会话 /etc/pam.d/sshd + limits.conf 重启 SSH 或重连
systemd 服务 /etc/systemd/system.conf 或服务文件的 LimitNOFILE systemctl daemon-reload + 重启服务
Docker 容器 ulimits 字段 重建容器
当前会话(临时) ulimit -n 65536 会话退出后失效

常见问题与注意事项

修改 limits.conf 后不生效

  1. 确认 SSH 会话是否重新登录:
# 查看当前会话的 PAM 配置
cat /etc/pam.d/sshd | grep pam_limits
  1. 检查是否受 systemd 用户实例限制:
# 查看用户登录时的限制
systemctl --user show | grep LimitNOFILE
  1. 对于 SSH 登录用户,确保 /etc/ssh/sshd_config 中未设置 UsePAM no

ulimit 设置后超过系统限制报错

确保 fs.file-maxfs.nr_open 设置的值大于 ulimit 设置的值:

# 查看系统最大值
cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open

Nginx 提示 “too many open files”

# 确认 Nginx 服务限制
systemctl show nginx | grep LimitNOFILE

# 如未生效,在 nginx.conf 中添加
worker_rlimit_nofile 65536;

# 确保 systemd 服务配置了 LimitNOFILE
sudo vi /usr/lib/systemd/system/nginx.service
# 添加 LimitNOFILE=65536
sudo systemctl daemon-reload
sudo systemctl restart nginx

参考链接