tp8在swoole协程下连接池耗尽本质是三层不匹配:mysql max_connections、swoole worker_num与协程并发量未对齐,需逐层检查并合理配置池参数,禁用pdo、改用databasepool,避免连接泄漏。

TP8 在 Swoole 协程环境下数据库连接池耗尽,本质是“请求要的连接数 > 池里能提供的连接数”,不是简单调大 max_connections 就能解决。关键得对齐三层:应用层池配置、Swoole 运行参数、MySQL 服务上限。
检查并拉齐三层限制
连接池耗尽往往卡在最短板。必须逐层确认:
-
MySQL 侧:执行
SHOW VARIABLES LIKE 'max_connections';,确保它 ≥ 池配置的max_connections(比如池设 50,MySQL 至少要 60,留缓冲) -
Swoole Worker 数:查看
swoole.server.worker_num配置。若设为 4,那最多只有 4 个进程能并发从池里取连接——哪怕池里有 100 个,也用不上。建议设为 CPU 核数的 1–2 倍 -
协程并发量:
go(function () { ... })启的协程数若远超池大小,就会排队等待。压测时可用echo \Swoole\Coroutine\Channel::stats();查当前等待队列长度
合理设置池参数
池大小不是越大越好,需兼顾复用率与内存开销:
-
min_connections:设为 5–10,避免首请求冷启动延迟;太高会空占 MySQL 连接 -
max_connections:推荐按worker_num × 平均每 worker 并发协程数估算。例如 8 个 worker、平均每个处理 8 个协程,池设 64 较稳妥;超过 100 易触发 OOM -
wait_timeout:设 2–5 秒。太小导致协程频繁抛ConnectionPoolTimeoutException;太大让请求干等无意义 -
heartbeat:设 30 秒,定期探测连接健康状态,避免脏连接堆积
代码层规避连接泄漏
池再大,用完不还也会耗尽:
- 禁用
Db::connect()和Db::table(),它们在协程中仍走 PDO,无法复用连接 - 改用
think-swoole提供的DatabasePool:$db = app('db'); $result = $db->query('SELECT * FROM user WHERE id = ?', [$id]); - 所有数据库操作后必须显式归还连接——
DatabasePool会自动处理,但自定义池需手动$pool->put($mysql) - 避免在构造函数、同步中间件、定时任务里提前执行 DB 操作,协程切出后连接易丢失
驱动与事务适配
错用驱动或事务方式会直接导致连接卡死:
- 必须关闭 PDO 模式:
'use_pdo' => false,启用mysqlnd + swoole_mysql兼容层(think-swoole默认已做) - 禁用
Db::transaction(),改用$db->startTrans()→$db->commit()或$db->rollback() - 不要混用
think-orm和旧版think-db,二者协程事务接口不兼容











