高并发场景下修改 Linux 文件描述符限制,需区分临时会话、用户永久配置、systemd 服务及内核全局上限四个层面。最推荐通过/etc/security/limits.conf 配置用户级限制,并为 systemd 服务单独设置 LimitNOFILE,同时调整内核参数 fs.file-max 确保系统级上限充足。
先说结论:解决 Too many open files 错误需同时调整用户级限制、服务级配置和内核全局上限,仅修改 ulimit 临时生效且重启失效。
- 适合:运行 Nginx、MySQL、Node.js 等高并发服务的 Linux 服务器
- 先准备:确认当前软限制 ulimit -Sn 和硬限制 ulimit -Hn,检查 systemd 服务是否托管
- 验收:重启服务后通过 cat /proc/<pid>/limits 验证进程实际限制值
命令速用版
以下命令用于快速查看和临时调整当前会话限制,适用于调试场景,重启终端后失效。
# 查看当前软限制
ulimit -Sn
# 查看当前硬限制
ulimit -Hn
# 临时提升软限制至 65535
ulimit -Sn 65535
# 查看系统级全局上限
cat /proc/sys/fs/file-max
# 临时提升系统级上限
sysctl -w fs.file-max=1048576为什么会这样
Linux 默认文件描述符限制较低是为了防止单个进程耗尽系统资源,但高并发服务需要同时维持大量网络连接和文件打开状态。每个网络连接、打开的文件都会占用一个文件描述符,默认值通常为 1024,一旦并发连接数超过该值,进程会报错 Too many open files 并拒绝新连接。调整限制需区分用户级、进程级和内核级,因为不同启动方式的服务生效配置不同。
分步处理
按作用域从临时到永久、从用户到系统逐级配置,确保所有层面均无瓶颈。
1. 临时修改当前 Shell 会话
适用场景:快速验证配置是否生效,无需重启服务。操作动作:在终端执行 ulimit 命令。风险边界:仅对当前终端及其子进程生效,关闭终端即失效。
ulimit -Sn 65535
ulimit -Hn 655352. 永久修改用户级限制
适用场景:所有通过该用户登录启动的进程。操作动作:编辑/etc/security/limits.conf 文件。风险边界:修改后需重新登录用户或重启服务,systemd 托管的服务可能不读取此配置。
# 编辑配置文件
sudo nano /etc/security/limits.conf
# 文件末尾添加(以 www-data 用户为例)
www-data soft nofile 65535
www-data hard nofile 65535
# 对所有用户生效可替换为通配符*
* soft nofile 65535
* hard nofile 655353. 配置 systemd 服务限制
适用场景:由 systemd 管理的 Nginx、MySQL 等服务。操作动作:修改服务单元文件或创建覆盖配置。风险边界:直接修改/usr/lib 下的文件会在软件升级时被覆盖,建议使用 systemctl edit。
# 创建覆盖配置目录
sudo mkdir -p /etc/systemd/system/nginx.service.d
# 编辑覆盖文件
sudo nano /etc/systemd/system/nginx.service.d/override.conf
# 写入以下内容
[Service]
LimitNOFILE=65535
# 重载配置并重启服务
sudo systemctl daemon-reload
sudo systemctl restart nginx.service4. 调整内核级全局上限
适用场景:高负载服务器,防止系统级文件句柄耗尽。操作动作:修改 fs.file-max 参数。风险边界:值过大可能增加内核内存开销,需根据物理内存合理设置。
# 临时生效
sudo sysctl -w fs.file-max=1048576
# 永久生效
echo "fs.file-max = 1048576" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p怎么验证是否生效
配置完成后需验证进程实际运行时的限制值,而非仅检查配置文件。
检查当前用户限制:执行 ulimit -n 确认新登录会话已加载新限制。
检查进程实际限制:找到服务进程 PID,执行 cat /proc/<pid>/limits | grep "Max open files",确认 Soft 和 Hard 值均已更新为设定值。
检查系统级使用率:执行 cat /proc/sys/fs/file-nr,第一个值为已分配句柄数,第三个值为系统上限,确保已分配数远小于上限。
常见坑
配置未生效通常是因为作用域混淆或加载顺序问题,以下是高频错误点。
Systemd 服务忽略 limits.conf:由 systemd 启动的服务不读取/etc/security/limits.conf,必须在 service 文件中显式设置 LimitNOFILE,否则重启服务后限制仍为默认值。
硬限制低于软限制:设置软限制时不能超过硬限制,普通用户无法自行提高硬限制,需 root 权限或在 limits.conf 中预先定义硬限制。
未重新登录或重载配置:修改 limits.conf 后需重新登录用户,修改 sysctl.conf 后需执行 sysctl -p,修改 systemd 配置后需 daemon-reload。
PAM 模块未启用:部分系统需在/etc/pam.d/common-session 中确认存在 session required pam_limits.so,否则 limits.conf 不生效。
常见问题
软限制和硬限制有什么区别?
软限制是当前生效值,进程可动态调整但不能超过硬限制;硬限制是上限值,通常只有 root 用户能提高硬限制。
为什么修改了 limits.conf 服务重启后没生效?
因为 systemd 管理的服务不读取 limits.conf,需在/etc/systemd/system/服务名.service.d/override.conf 中设置 LimitNOFILE。
fs.file-max 和 ulimit 限制有什么关系?
fs.file-max 是内核允许系统打开的文件描述符总数上限,ulimit 是单个用户或进程的上限,单个进程限制不能超过系统总上限。
修改后需要重启服务器吗?
不需要重启服务器,但修改 limits.conf 后需重新登录用户,修改 systemd 配置后需重启对应服务,修改 sysctl 后需执行 sysctl -p。
参考来源
Linux 怎么设置 ulimit 限制_Linux ulimit 修改文件描述符教程【进阶】
linux 怎么修改最大文件限制_linux 优化内核参数【指南】
Linux 文件描述符限制_ulimit 配置方法
Linux 怎么设置文件描述符上限_Linux limits.conf 配置教程【性能】
Linux 如何实现服务高并发处理能力_Linux 系统参数优化
Linux 修改最大文件描述符数文件
简单修改 Linux 系统文件描述符限制 (Too many open files)
并发时 - 修改 Linux 系统下的最大文件描述符限制 - 博客园
Linux 系统文件描述符限制配置指南_linux 文件描述符限制-CSDN 博客
深入理解 Linux 系统中的文件描述符与进程数限制