PHP无原生连接池,mysqli/PDO每次new均为新TCP连接;pconnect仅进程内复用且不推荐生产使用;Swoole协程MySQL(Co\MySQL)通过异步I/O实现轻量“伪池”;ProxySQL是唯一成熟外部连接池方案。

PHP 本身没有原生连接池,mysqli 和 PDO 每次 new 都是新 TCP 连接
PHP-FPM 模式下,每个请求结束就销毁所有资源,mysqli 的 pconnect 只是在进程内复用,不是跨请求的“池”。它依赖 PHP 的持久连接机制(如 mysql.allow_persistent),但实际中容易因超时、状态残留、事务未提交等问题导致连接不可靠,官方文档也明确标注为“不推荐用于生产”。
常见错误现象:MySQL server has gone away、Commands out of sync、连接数突增却没被回收。
-
pconnect在 CLI 或 Swoole Worker 中基本失效——Worker 不重启,连接不会自动释放,反而堆积 - 即使开启
mysqlnd的mysqlnd_ms插件,也只是读写分离+故障转移,不是连接池 - FPM 下用
static $conn手动缓存?不行。FPM 是多进程模型,进程间不共享内存,缓存只在单个请求生命周期内有效
Swoole 协程 + Co\MySQL 是目前最轻量可靠的“伪池”方案
协程 MySQL 客户端(Co\MySQL)底层使用异步 I/O,连接可被多个协程并发复用,且支持连接自动重连和超时控制。它不叫“池”,但行为上接近:一个 Worker 内维护若干空闲连接,按需分配、用完归还、超时回收。
使用场景:Swoole HTTP Server、Task Worker、定时任务等长生命周期服务。
立即学习“PHP免费学习笔记(深入)”;
- 必须启用
enable_coroutine => true(Swoole 4.4+ 默认开启) - 不要在协程外调用
Co\MySQL::connect(),会阻塞整个 Worker - 连接对象不能跨协程传递,但可以封装成
ConnectionPool类管理Defer归还逻辑 - 示例关键片段:
$pool = new ConnectionPool(function () { $mysql = new Co\MySQL(); $mysql->connect([ 'host' => '127.0.0.1', 'user' => 'root', 'password' => '', 'database' => 'test', 'timeout' => 2, ]); return $mysql; }, 10); // 最大 10 个连接 go(function () use ($pool) { $db = $pool->get(); $result = $db->query('SELECT id FROM user LIMIT 1'); $pool->put($db); // 必须手动归还 });
ProxySQL 是唯一能在 PHP 外部真正实现连接池的成熟方案
它运行在数据库和应用之间,对 PHP 完全透明。PHP 还是用普通 PDO 或 mysqli 连 ProxySQL 的 6033 端口,ProxySQL 自己管理后端 MySQL 的连接池、读写分离、熔断、慢查询拦截。
性能影响:增加一次网络跳转(通常
- ProxySQL 的
mysql-pool默认开启,max_connections控制后端连接上限,min_idle_connections控制保活连接数 - 常见坑:
wait_timeout和interactive_timeout必须大于 ProxySQL 的mysql-server_version和mysql-connect_timeout_server_max,否则连接被 MySQL 主动断开后 ProxySQL 不会自动重连 - PHP 连接字符串里 host 改成
127.0.0.1:6033,密码/库名不变;ProxySQL 管理接口默认6032,用admin/admin登录配置后端 - 不建议用
mysqlnd_ms或sharding-proxy替代——前者无池,后者太重、协议兼容差
别把连接池和连接复用混淆:Swoole 协程解决的是“单 Worker 内复用”,ProxySQL 解决的是“全集群连接收敛”
很多项目卡在“为什么用了 pconnect 还是频繁创建连接”,本质是没分清作用域:FPM 进程间无法共享,协程内可共享,ProxySQL 在系统层共享。
最容易被忽略的一点:Swoole 的 Co\MySQL 不支持存储过程中的多结果集(more_results),如果业务重度依赖 CALL proc(),必须切到 ProxySQL + 普通 PDO,并开启 PDO::MYSQL_ATTR_MULTI_STATEMENTS。











