必须同时调用户级、系统级、内核级三处参数:修改/etc/security/limits.conf设软硬限制、systemd服务需在unit文件中配limitnofile、sysctl调fs.file-max和net.core.somaxconn。

Linux系统默认的连接数限制极低,ulimit -n 显示 1024 是常见现象,但这意味着单个进程最多只能建立约 1014 个 TCP 连接(扣除 stdin/stdout/stderr、监听 socket 等固定开销)。真正想跑万级并发服务,必须同时调用户级、系统级、内核级三处参数,缺一不可。
ulimit -n 不生效的典型原因
执行 ulimit -n 65536 却报 Operation not permitted,不是命令写错,而是软/硬限制没提前放开。Linux 要求:当前会话的 ulimit 设置不能超过 limits.conf 中定义的硬限制(hard nofile),而硬限制又不能超过系统级上限 /proc/sys/fs/file-max。
- 先确认当前硬限制:
ulimit -Hn;若低于目标值,需改/etc/security/limits.conf - 普通用户修改后需重新登录(SSH 重连)才生效,
su -不触发 pam_limits - systemd 服务(如 nginx、redis)默认不读
limits.conf,必须在 service 文件中显式加LimitNOFILE=65536或全局设DefaultLimitNOFILE - 检查
/etc/pam.d/common-session是否含session required pam_limits.so(Ubuntu/Debian 系默认有;CentOS 需确认/etc/pam.d/login或system-auth)
/etc/security/limits.conf 的关键写法
很多人照抄 * soft nofile 65536 却发现 root 进程仍卡在 1024 —— 因为 * 不匹配 root,且 systemd 会绕过该文件。
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
- 对 root 显式写:
root soft nofile 65536和root hard nofile 65536 - 若服务以非 root 用户运行(如
www-data),必须写对应用户名,不能只靠* -
soft值必须 ≤hard值,否则登录时 pam_limits 会静默忽略整行 - 该文件只影响通过 PAM 登录的交互式会话,对
systemctl start启动的服务无效
systemd 服务的文件描述符设置
现代 Linux 发行版(CentOS 7+/Ubuntu 16.04+)用 systemd 管理服务,limits.conf 对它们完全无效。必须直接配置 unit 文件。
- 全局生效(推荐):
sudo systemctl edit --full systemd-system.conf,添加:DefaultLimitNOFILE=65536
- 单服务生效(更安全):
sudo systemctl edit nginx.service,添加:[Service] LimitNOFILE=65536
- 改完必须重载:
sudo systemctl daemon-reload,再sudo systemctl restart nginx - 验证是否生效:
cat /proc/$(pgrep nginx)/limits | grep "Max open files"
内核参数 fs.file-max 和 net.core.somaxconn
fs.file-max 是系统总文件句柄上限,所有进程加起来不能超这个数;net.core.somaxconn 是 listen socket 的等待队列长度,直接影响新连接接纳能力。两者都必须调,但目的不同。
-
fs.file-max应设为单进程最大值 × 进程数 × 1.2 安全余量(例如 65536 × 4 × 1.2 ≈ 314572);写入/etc/sysctl.conf:fs.file-max = 314572
-
net.core.somaxconn必须 ≥ 应用 listen() 的backlog参数(如 nginx 的listen ... backlog=4096),建议设为 65535 - 短连接场景务必开
net.ipv4.tcp_tw_reuse = 1,否则TIME_WAIT堆积会快速耗尽本地端口 - 改完运行
sudo sysctl -p生效,无需重启
最易被忽略的是:调完所有参数后,必须用 lsof -p PID | wc -l 实测进程真实打开数,而不是只信 ulimit -n 输出 —— 因为后者只是“允许上限”,实际能开多少,还取决于内存、端口范围、应用自身逻辑是否及时 close()。










