Swoole中static变量在onRequest里持续递增是因Worker进程常驻导致生命周期为进程级;正确做法是用SwooleTable或Redis实现请求隔离,禁用全局静态状态。
Swoole 在唯品会这类高并发电商场景中,不是“能不能用”的问题,而是“怎么用才不出事”的问题。真实压测和线上事故反复验证:协程写法稍有偏差、连接没回收、状态没隔离,流量一上来就内存暴涨或请求串号。onRequest 里定义 static $counter 会越加越大这不是 bug,是 Swoole Worker 进程常驻的必然结果。PHP-FPM 每次请求都重载脚本,static 变量自然重置;而 Swoole 的 onRequest 回调在同一个 Worker 进程内反复执行,static 存储的是进程级生命周期数据。
static 变量不会自动清空,也不受请求上下文约束SwooleTable(单机)或 Redis(跨进程),例如:$table->incr($key, 'count', 1)
$_SERVER 或 $GLOBALS 存临时数据,同样会跨请求污染SwooleRuntime::enableCoroutine() 必须在哪儿调用必须在所有业务代码执行前、且仅一次调用,通常放在 Server 启动入口最顶部,不能放在 onRequest 或协程函数内部。
go(function () { SwooleRuntime::enableCoroutine(); ... }); —— 此时协程环境已存在,Hook 失效,curl_exec 仍阻塞$server->start() 前,全局作用域第一行写 SwooleRuntime::enableCoroutine(true);
true 表示 Hook 所有支持的函数(含 file_get_contents、stream_socket_client 等),但 sleep() 仍需换为 SwooleCoroutine::sleep()
Too many open files
协程 MySQL 客户端实例本身不自动释放底层 socket,unset($client) 不等于关闭连接,必须显式调用 close()。
$db = new SwooleCoroutineMySQL(); $db->connect(...); 后直接 return,没 $db->close()
EMFILE 错误try/finally 包裹,确保无论是否异常都执行 $db->close()
return 到空闲队列,避免频繁 connect() 开销onTask 里用了 global 变量会怎样TaskWorker 是独立进程,与 Worker 进程内存完全隔离。global 变量在 TaskWorker 内是全新副本,修改它对 Worker 无任何影响,但容易误以为能共享状态。
立即学习“PHP免费学习笔记(深入)”;
global $cache = [];,投递任务后在 onTask 里往 $cache[] push 数据,期望 Worker 能读到 —— 实际读到的是空数组onTask 里调用 SwooleCoroutine 相关函数(如 go),TaskWorker 默认不启用协程环境,需手动 SwooleCoroutinerun() 包裹