Swoole 5协程MySQL连接池空闲连接不会自动回收,需开发者实现ping校验归还与后台协程定期清理,并同步调整MySQL的wait_timeout等参数。

在 Swoole 5 中使用协程 MySQL 连接池时,空闲连接不会自动回收——Channel 本身不提供空闲超时或定时清理机制。所谓“自动回收”,必须由开发者主动实现健康检查与归还逻辑,否则连接会一直驻留内存,可能引发资源泄漏、TIME_WAIT 堆积或 MySQL 端因 wait_timeout 主动断连后连接失效等问题。
空闲连接回收的核心逻辑
真正可控的“回收”发生在两个环节:连接归还时的校验丢弃,以及后台协程定期扫描清理。Swoole 5 的 Swoole\Coroutine\Channel 仅负责队列式存取,不带生命周期管理,因此需手动补全:
- 每次归还连接前,先调用
$mysql->ping();失败则直接unset或丢弃,不 push 回池 - 启动一个独立协程(如
go(function () { ... })),每隔 30–60 秒遍历池中连接,对长时间未使用的连接执行close()并从 Channel 中移除 - 避免复用已 close 的连接句柄:归还时若发现
$mysql->connected === false或 ping 失败,应新建连接替代,而非重连旧实例
推荐的池初始化 + 回收结构示例
以下代码片段体现关键回收策略(含 ping 校验、超时归还、后台清理):
// 初始化池(容量 32)
$pool = new Swoole\Coroutine\Channel(32);
$config = ['host' => '127.0.0.1', 'user' => 'root', 'password' => '', 'database' => 'test'];
// 预创建连接
for ($i = 0; $i < 32; $i++) {
$mysql = new Swoole\Coroutine\MySQL();
if ($mysql->connect($config)) {
$pool->push($mysql);
}
}
// 后台清理协程:每 45 秒扫描一次,清理空闲超 5 分钟的连接
go(function () use ($pool) {
while (true) {
\co::sleep(45);
// 实际项目中建议用带时间戳的包装对象,此处简化为统计+重建
$newPool = new Swoole\Coroutine\Channel(32);
while ($pool->length() > 0) {
$mysql = $pool->pop();
// 若 ping 失败或连接明显异常,跳过归还
if ($mysql->ping()) {
$newPool->push($mysql);
}
}
$pool = $newPool;
}
});
配合 MySQL 服务端参数协同生效
空闲回收效果依赖客户端与服务端行为一致。务必同步检查并调整以下参数:
-
wait_timeout(MySQL 默认 28800 秒 / 8 小时):建议设为 300–600 秒,与你的清理周期匹配 -
interactive_timeout:若连接带CLIENT_INTERACTIVE标志,也需同步调低 - PHP 层避免设置过长的
maxLifetime(如 30 分钟),否则清理协程可能滞后于 MySQL 断连时刻
不要依赖的“伪回收”方式
这些做法看似省事,但实际不可靠或有副作用:
- 用
$mysql->close()后再 push 回池:close 会释放 fd,push 的是无效对象,下次 pop 出来必报错 - 仅靠
$mysql->connected判断状态:该属性只反映 connect 调用结果,不感知服务端断连 - 设置
Channel::pop(0)并忽略超时:会导致连接永远滞留,无法触发回收逻辑 - 依赖 Swoole 自动 GC 协程变量:协程退出时若未显式 close,fd 不释放,仍占用系统资源


















