Swoole参数调优需匹配资源实际水位:worker_num宜设为CPU核数1–2倍,task_worker_num≤worker_num×2;max_coroutine和coroutine_stack_size应依压测结果调整;reload_async生效需满足版本≥4.8.13、非守护模式等条件;ProcessPool进程数受RLIMIT_NPROC限制。

为什么 swoole_server->set() 里的 worker_num 和 task_worker_num 不能随便调高
调高 worker_num 并不等于并发能力线性提升,反而容易触发系统资源瓶颈。Swoole 的 worker 进程是常驻的,每个都独占内存(含 PHP 扩展、加载的类、协程栈等),worker_num=100 在大项目里可能直接吃掉 2–3GB 内存;而 task_worker_num 过高会加剧进程间通信(IPC)压力,尤其用 msgqueue 模式时,队列积压、超时、丢任务都可能出现。
实操建议:
-
worker_num推荐设为 CPU 核心数的 1–2 倍(例如 4 核机器设4或8),IO 密集型可略高,CPU 密集型必须保守 -
task_worker_num不要超过worker_num * 2,且必须配合task_max_request(防内存泄漏)和task_tmpdir(确保 tmpfs 可写) - 改完必须用
ps aux | grep php看实际进程数,确认没被 systemd 或 supervisor 拦截重载
协程环境下 max_coroutine 和 coroutine_stack_size 怎么配才不崩
这两个参数管的是协程调度器的底层资源,不是“开越多越好”。max_coroutine 设太大,一旦并发协程全卡在 IO 等待或死循环里,调度器会耗尽内存;coroutine_stack_size 默认 256KB,但某些扩展(比如 Redis、PDO)在协程中调用时会隐式放大栈用量,设太小会直接报 coroutine stack overflow。
实操建议:
- 新项目起步用默认值(
max_coroutine=3000,coroutine_stack_size=256K),压测时观察swoole_get_status()返回的coroutine_num和coroutine_peak_num - 如果频繁出现
coroutine stack overflow,优先检查是否在协程里用了sleep()、usleep()或阻塞函数,而不是盲目调大coroutine_stack_size - PHP 8.1+ 启用
ZEND_SIGNAL=0环境变量可降低栈消耗,适合高密度协程场景
热重启时 reload_async 开关不生效?先查这三件事
reload_async=true 是让 reload 不阻塞新请求,但它依赖底层信号处理和进程状态同步。很多情况下它看似“没用”,其实是被其他配置或运行态干扰了。
实操建议:
- 确认 Swoole 版本 ≥ 4.8.13(旧版
reload_async有竞态 bug) - 必须关闭
daemonize=true,否则主进程无法响应 SIGUSR1 信号;若要用守护进程,得靠 systemd 的ReloadSignal=SIGUSR1配合 - 检查
onWorkerStart里有没有阻塞操作(如未加超时的curl_exec、数据库连接池初始化失败重试),这些会让 worker 卡住,导致 reload 卡在 “waiting for worker exit”
用 ProcessPool 手动管理子进程时,max_process_num 和系统 RLIMIT_NPROC 的关系
ProcessPool 不走 Swoole 内置 worker 生命周期,它的进程数直接受 Linux 用户级进程限制约束。即使代码里设了 max_process_num=50,如果当前用户 RLIMIT_NPROC 是 40,第 41 个进程会创建失败,报 fork failed: Resource temporarily unavailable,且不会抛异常,只默默跳过。
实操建议:
- 启动前用
ulimit -u查当前限制,生产环境建议在 systemd service 文件里加LimitNPROC=65535 -
ProcessPool的max_process_num应 ≤ulimit -u的 70%,留余量给 PHP 主进程、日志轮转、crond 等其他子进程 - 务必监听
onWorkerError,打印$worker->pid和$worker->exit_code,exit_code=12就是 fork 失败的典型信号
事情说清了就结束。真正卡住性能的,往往不是参数数字本身,而是参数背后那个没被监控到的资源水位——比如 task 进程的内存持续上涨、协程栈在某次 Redis pipeline 调用后悄悄翻倍、或者 ulimit 在容器里被 cgroup 二次覆盖。调参前,先看 swoole_get_status() 和 cat /proc/$(pgrep php)/limits。










