laravel在php-fpm下无法实现真正连接池,因pdo连接绑定单请求生命周期;仅swoole/roadrunner等常驻进程环境支持协程级复用,需配置pool参数、db_host为ip并使用对应启动命令。

连接池在 Laravel 中不能“直接启用”,它依赖运行环境是否支持长连接复用——PHP-FPM 下所有所谓“连接池”都是伪方案,只有 Swoole、RoadRunner 或 PHP-PM 这类常驻进程环境才能真正实现连接复用。
为什么 FPM 环境下配不了真正的连接池
Laravel 底层用 PDO,而 PDO 实例生命周期绑定于单个 PHP-FPM 进程的请求周期。请求结束,连接就 close;下个请求进来,哪怕同一进程,PDO 也大概率重建(除非显式用了 persistent => true,但那只是进程内复用,不跨请求,且易引发状态残留)。你看到的 SQLSTATE[HY000] [1040] Too many connections,本质是 MySQL 的 max_connections 被瞬时打满,不是 Laravel “没配对”,而是 FPM 子进程数 × 并发请求数 > 数据库承载上限。
- 别信“在
config/database.php加pool数组就能开连接池”的教程——Laravel 官方不识别该配置项,纯属误导 -
DB::reconnect()或DB::disconnect()对连接数控制无效,甚至可能让连接泄漏更隐蔽 - FPM 场景下真正该调的是 MySQL 的
wait_timeout(建议设为60)和 PHP 的pm.max_children,而非折腾“池”
Swoole 环境下启用协程连接池(唯一推荐路径)
只有在 Swoole 常驻进程中,每个 Worker 才能持有一组独立、可被协程并发复用的长连接。此时连接池才具备实际意义。
- 确认已安装
swooletw/laravel-swoole,且 Swoole 版本 ≥ 4.8.0 - 在
config/database.php的mysql配置块中加入:'pool' => [ 'min_connections' => 5, 'max_connections' => 20, 'wait_timeout' => 3, 'max_lifetime' => 120, ], - 确保
.env中DB_HOST是 IP(如127.0.0.1),避免 Unix socket 导致连接池失效 - 启动命令必须是
php bin/laravels start,而不是php artisan serve或 FPM - 验证方式:压测时执行
SHOW PROCESSLIST,连接数应稳定在 Worker 数 ×min_connections附近,而非随 QPS 暴涨
MongoDB 和 Redis 连接池配置差异大,别混用参数
MongoDB 驱动(如 mongodb/mongodb)原生支持连接池参数,Redis 则取决于客户端:PhpRedis 不提供池,靠 pconnect() 复用;Predis 在 Swoole 下需自定义 FactoryInterface 才能协程池化。
- MongoDB:
maxPoolSize控制并发上限,默认 10,建议设为 CPU 核数 × 2~4;minPoolSize建议为maxPoolSize的 1/4;maxIdleTimeMS推荐300000(5 分钟) - Redis + PhpRedis:
'persistent' => true+REDIS_CLIENT=phpredis即可,无需额外池配置 - Redis + Predis + Swoole:必须写
Predis\Connection\FactoryInterface实现,用Swoole\Coroutine\Channel管理连接,官方不提供开箱即用方案
ProxySQL / Twemproxy 是最稳妥的兜底方案
如果你无法改造 PHP 运行环境(比如托管在传统 FPM 主机上),又必须缓解连接风暴,代理层是最可控的选择——它完全解耦应用逻辑,MySQL 侧看到的永远是固定数量的连接。
- ProxySQL 默认监听
6033,配置mysql_servers指向真实 MySQL,并设置max_connections限流 - Twemproxy 更轻量,适合 Redis,配置
max_connections: 500即可拦截上游连接洪峰 - 改
.env:把DB_HOST指向代理地址,其他不变,零代码修改 - 风险点:代理本身单点故障,务必加监控(如
proxysql-admin --monitor)和 failover 机制
真正难的不是配参数,而是判断当前瓶颈到底出在哪一层:是慢查询拖住连接?是 FPM 子进程数远超数据库承受力?还是 Swoole Worker 数设得太小导致池子根本没被填满?先用 SHOW PROCESSLIST 和 EXPLAIN FORMAT=JSON 看清现场,再动手调池。











