协程连接池必须在onWorkerStart初始化,每个Worker进程独立维护池实例;获取连接后须显式put()归还而非close(),漏归还将导致泄漏;需在get()后ping()检查有效性,并用defer或finally确保归还。

协程连接池必须在 onWorkerStart 里初始化
每个 Worker 进程要独立维护自己的连接池,不能在 onRequest 或协程里 new 一次——否则每请求都新建池,连接数爆炸,Too many connections 立刻报给你看。
正确做法是:在 Swoole\Http\Server 的 onWorkerStart 回调中,为当前 Worker 初始化一个池实例,并存到全局变量或 Server->set() 的属性里。后续所有协程都复用这个池。
- 错例:
go(function () { $pool = new MyPool(); ... });—— 每次 go 都 new,池无效 - 对例:
$server->on('workerStart', function ($server, $workerId) { $server->pool = new \Swoole\Coroutine\Channel(64); ... }); - 注意:不要用
static或global变量跨 Worker 共享池,Swoole 多进程下会冲突
获取连接后必须显式归还,不能 close()
Swoole\Coroutine\MySQL 或 \Swoole\Database\PDOPool 的连接对象不是“用完即焚”,close() 会彻底销毁连接,导致池里连接越来越少,最终耗尽;正确操作是 put($conn) 或 $channel->push($conn)。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 漏归还 = 连接泄漏,压测几分钟后
max_connections就被打满 - 异常分支(try/catch/finally)里也得确保归还,推荐用
defer或 finally 块包裹put() - 如果用了
\Swoole\Database\PDOPool,它提供get()/put(),但注意put(null)用于标记失效连接,避免污染池
别直接替换 PDO 驱动就想自动协程化
TP8.1 改 'type' => 'mysqlnd'、Yii2 直接换 PDO 类,都不行。PDO 扩展本身不支持协程,底层仍是阻塞 syscall,协程环境里它会退化成同步 IO,连接池形同虚设。
- ThinkPHP:必须配合
think-swoole ≥3.1.0+Db::pool()显式调用,否则模型查询绕过池 - Yii2:根本没法兼容,必须绕过
yii\db\Connection,改用Swoole\Coroutine\MySQL或封装好的池(如swoole/mysql-pool) - 原生 Swoole:只认
Swoole\Coroutine\MySQL或\Swoole\Database\PDOPool,和 PDO_MySQL/PDO_Mysqlnd 都不兼容
连接有效性检查不能省,尤其长时间空闲后
MySQL 默认 wait_timeout=28800(8 小时),但实际网络抖动、中间件断连更常见。从池里取出的连接可能已失效,直接 query 会报 MySQL server has gone away 或错误码 2006/2013。
- 每次
get()后建议先$conn->ping(),失败则重建连接再入池 - 连接对象上记录
last_used_time,归还前判断是否超时(如 >300 秒),超时则 close 并新建 - 不要依赖 MySQL 的 auto-reconnect:协程池里开启它反而掩盖问题,且事务上下文无法恢复

















