不算。PHP-FPM下PDO::ATTR_PERSISTENT仅为进程级连接复用,每个worker独占连接、不共享不调度,非真正连接池;需DSN/用户/密码完全一致、wait_timeout合理配置,并手动清理事务等状态。

PHP-FPM 下用 PDO::ATTR_PERSISTENT 真的算“连接池”吗
不算。它只是进程级连接复用,每个 PHP-FPM worker 进程持有一个独立的 MySQL 连接,不共享、不调度、不回收空闲连接。本质是「伪池化」,但对中低并发(QPS
- 启用方式必须显式传入
PDO::ATTR_PERSISTENT => true,缺省值为false - 连接字符串中的 host 必须写死 IP(如
127.0.0.1),不能用localhost(会走 socket,持久化失效) - MySQL 侧的
wait_timeout必须 ≥ PHP 进程平均存活时间,否则连接被 DB 主动断开后,下次复用会报错MySQL server has gone away - 事务、临时表、用户变量等状态不会自动清理(PDO 不做
mysql_change_user()),需在脚本末尾显式$pdo->rollBack()或$pdo->exec('RESET SESSION')
ThinkPHP6 开启 deploy => 1 后连接数还是飙升
因为 TP6 的「连接池」逻辑只对「完全相同配置 + 同数据库名」生效。只要请求里切换了 database、username 或 hostport,就会新建一个连接池实例,导致连接堆积。
- 检查日志中是否频繁出现不同
database名称的连接请求(比如多租户动态切库) -
pool_size是最大空闲连接数,不是总连接上限;若未设,TP6 默认不限制,容易撑爆max_connections - 冷启动时所有请求同时触发连接创建,建议搭配
min_connections预热,但 TP6 原生不支持该参数,需自行扩展或改用 Hyperf - 务必关闭调试模式(
debug => false),否则 TP6 会在每次查询后调用SHOW FULL PROCESSLIST,额外占用连接
Swoole 协程连接池的 max_idle_time 设多少才安全
60 秒是通用起点,但必须和网络链路、MySQL wait_timeout、中间设备(如 SLB、防火墙)的空闲超时取最小值。设大了,连接会被中间层静默断开;设小了,高频重建连接反而拖慢吞吐。
- 先查 MySQL 当前设置:
SHOW VARIABLES LIKE 'wait_timeout';(默认 28800,但生产环境常调为 300–600) - 再确认代理层(如 ProxySQL、阿里云 RDS 代理)的空闲超时,常见为 300 秒;若用云厂商 SLB,查其 TCP 空闲超时(腾讯云默认 900,AWS NLB 默认 3600)
-
max_idle_time应 ≤ 上述所有环节最小值 − 5 秒,留出检测与重连缓冲 - 必须开启健康检测:
ping_on_get => true,否则拿到已断连会直接抛异常,而不是自动重建
为什么开了连接池,Threads_connected 还是持续上涨
大概率是连接没归还。Swoole/Hyperf 的连接池依赖「使用完主动 release」或「协程结束自动回收」,但若协程 panic、异常退出、或手动 unset($conn),连接就永远滞留在池中。
立即学习“PHP免费学习笔记(深入)”;
- 检查代码里是否有
try/catch捕获异常后忘记$pool->release($conn) - 禁用
gc_disable()类操作,协程退出时 GC 可能延迟触发,导致连接未及时归还 - 用
SHOW STATUS LIKE 'Threads_connected';定期观察,配合SELECT * FROM information_schema.PROCESSLIST WHERE TIME > 60;找出僵死连接 - Hyperf 用户注意:若用
@Inject注入ConnectionInterface,框架会自动管理生命周期;但若手动 newCo\MySQL,则必须自己负责 release
连接池不是一配就灵的开关,关键在「连接生命周期是否真正闭环」——从获取、使用、异常处理到归还,每一步都可能漏掉。最容易被忽略的是跨协程传递连接对象后,在目标协程里忘了释放。



















