Workerman报Too many open files错误是因系统对单进程文件描述符限制过低所致,需依次检查并调整ulimit、/etc/security/limits.conf、systemd或supervisord配置、内核参数及Workerman自身maxConnections设置,确保各层一致且生效。

Workerman报 Too many open files 怎么办
Workerman 进程启动后突然拒绝新连接,日志里反复出现 Too many open files 错误,本质是系统对单个进程能打开的文件描述符(file descriptor)数量做了限制,而 Workerman 的每个 TCP 连接、监听 socket、定时器、甚至部分日志句柄都会占用一个 fd。默认 Linux 限制通常是 1024,远不够高并发场景。
- 先用
ulimit -n查当前 shell 启动 Workerman 时的软限制(注意:不是系统全局值,而是启动那一刻继承的值) - 临时提高:在启动前执行
ulimit -n 65535,但仅对当前 shell 及其子进程有效 - 永久生效需改两处:
/etc/security/limits.conf(加www-data soft nofile 65535和www-data hard nofile 65535),以及 systemd 服务配置中加LimitNOFILE=65535(如果用systemctl管理) - 改完必须重启 Workerman 进程(不是 reload),因为 fd 限制只在进程 fork 时读取一次
为什么 ulimit -n 改了还是不生效
常见错觉是改了 /etc/security/limits.conf 就万事大吉,其实它只对通过 login shell 启动的进程生效。Workerman 若由 systemd、supervisord 或 crontab 启动,往往绕过了 PAM limits 加载流程,导致配置被忽略。
- systemd 用户务必检查服务单元文件(如
/etc/systemd/system/workerman.service)是否含LimitNOFILE=65535,且要执行systemctl daemon-reload && systemctl restart workerman - supervisord 需在
[program:workerman]段落里显式写environment=ULIMIT="ulimit -n 65535",再配command=/bin/sh -c "ulimit -n 65535 && php start.php start -d" - 用
cat /proc/<pid>/limits | grep "Max open files"</pid>直接查运行中 Workerman 主进程的实际限制值,这是唯一可信依据
max_connections 和系统 fd 限制是什么关系
Workerman 自身的 $worker->count 和 $worker->maxConnections 是应用层控制,它们不会自动适配系统 fd 上限。比如设了 maxConnections = 10000,但系统只给 4096 个 fd,Workerman 会在达到 4096 时静默失败——新连接进不来,也不报错,只卡在三次握手完成前。
-
$worker->maxConnections建议设为系统可用 fd 的 70%~80%,留余量给定时器、日志、DNS 查询等其他开销 - 用
lsof -p <pid> | wc -l</pid>实时观察 Workerman 进程实际占用 fd 数,对比cat /proc/<pid>/limits</pid>中的Max open files值 - 不要盲目把
maxConnections设成 65535 —— 即使系统允许,内核net.core.somaxconn和net.ipv4.ip_local_port_range也会成为瓶颈
Workerman 子进程 fd 共享吗
不共享。每个 Worker 子进程(包括主进程和所有 fork 出来的 worker)都有独立的 fd 表。所以总连接数上限 ≈ 子进程数 × 单进程最大 fd 数。这也是为什么不能只调高主进程限制就以为万事大吉。
- 用
ps aux | grep workerman看子进程数量,确认是否和代码中$worker->count一致 - 若用
Worker::setDaemonize(true),主进程会退出,此时所有 fd 由子进程各自持有,ulimit必须在子进程启动前设置好 - 调试时可临时关闭守护进程模式(
setDaemonize(false)),方便用ps和lsof跟踪具体哪个进程卡住了
/proc/<pid>/limits</pid>,再逆推哪一层没生效。









