不能,Hyperf 3.0 已彻底移除 worker_num 的语义和作用,配置无效;实际并发由 task_worker_num 和协程调度决定,应调整 task_worker_num(建议 CPU 核数×2~4)、开启 task_enable_coroutine=true,并通过 max_conn 和 max_request 控制连接与请求生命周期。

Hyperf 3.0 还能配 worker_num 吗?不能,别白改
不能。Hyperf 3.0 已彻底移除 worker_num 的语义和作用——它在 config/autoload/server.php 里写进去也不会生效,Swoole 5+ 协程 Server 模型下,已没有传统意义上的“Worker 进程”概念。你看到的进程列表里那些 php bin/hyperf.php start 启动的进程,实际是协程调度器管理下的轻量级协程执行单元,不是靠增减进程数来扩并发。
常见错误现象:ps aux | grep hyperf 看到进程数没变、压测 QPS 上不去、CPU 利用率卡在单核,却还在反复调 worker_num;或者改完配置重启服务,swoole_get_local_config() 打印出的 settings 里根本找不到 worker_num 字段。
- 真正起作用的是
task_worker_num(用于异步任务) + 协程并发数(由max_coroutine和业务逻辑决定) -
worker_num若强行保留,会被 Swoole 忽略或报 warning,但不 crash - 如果你用的是 Hyperf 2.x 升级到 3.0,务必删掉 config 中所有
worker_num相关配置项
max_request 是什么?不是防泄漏的万能开关
max_request 控制的是每个 Worker 协程(注意:不是进程)处理多少个请求后自动销毁重建。它确实能缓解内存缓慢增长,但不是“开了就稳”,更不是替代代码质量的兜底方案。
使用场景:长连接服务、中间件里用了未清理的静态缓存、ORM 查询结果未释放、日志对象反复 new 未 gc。
- 设为
0:永不重启协程,风险最高,适合极简无状态逻辑(如纯计算 API) - 设为
1000–5000:通用推荐区间,兼顾稳定性与重启开销 - 设为
100000或更高:仅当确认无内存泄漏且协程初始化成本极低时才考虑,否则重启延迟会拖慢请求 - 必须配合
reload_async => true,否则重启时会丢请求
为什么 max_request 设了还是 OOM?因为漏掉了 max_conn
max_conn 控制的是服务器同时接受的 TCP 连接上限,默认是 10000。它比 max_request 更早拦截流量,是第一道防线。很多人只调 max_request,结果连接数爆满,新请求直接被内核拒绝(SYN DROP),日志里连 error 都看不到。
性能影响明显:当 max_conn 被打满,后续请求会在客户端超时(Connection refused / timeout),而服务端 CPU 可能还很低——这不是性能瓶颈,是连接层过载。
- 高并发短连接(如 HTTP API):建议设为
20000–50000,视网卡和 ulimit -n 而定 - 长连接(如 WebSocket):必须严格限制,比如
5000,避免连接堆积耗尽内存 - 务必同步检查系统级限制:
cat /proc/sys/net/core/somaxconn和ulimit -n,两者都要 ≥max_conn
自定义进程里忘记 Coroutine::sleep() 就会吃满 CPU
Hyperf 自定义进程(继承 AbstractProcess)默认运行在独立的 PHP 进程中,**不自动启用协程调度器**。你在 handle() 里写 while(true) { doSomething(); },就是裸奔式死循环,一个进程就能把一个 CPU 核跑满。
容易踩的坑:以为加了 sleep(1) 就安全——错,sleep() 会阻塞整个进程,协程无法切换,依然卡死;必须用 Coroutine::sleep() 或 usleep() + 显式让出控制权。
- 正确写法:
while (true) { $this->doWork(); Coroutine::sleep(1); } - 错误写法:
while (true) { $this->doWork(); sleep(1); }(阻塞式,CPU 100%) - 更稳妥做法:加
Co::yield()或结合Channel等协程原语做事件驱动,而不是轮询
复杂点在于,自定义进程和 Task Worker 的生命周期模型不同,前者完全由你掌控,后者受 Swoole 内部调度约束;混用时尤其要注意上下文隔离——比如别在自定义进程里复用同一个 DB 连接实例。


















