ThinkPHP6 一万并发下数据库连接耗尽本质是短连接高频创建销毁失控,需协同优化连接生命周期、复用机制与请求调度:启用PDO持久连接、收紧PHP-FPM配置、显式控制连接获取释放,并增加超时降级与缓存兜底。

ThinkPHP6 在面对一万并发时,数据库短连接过多问题本质不是“并发高”,而是短连接在高频创建/销毁过程中失控,导致 MySQL 的 max_connections 被迅速耗尽,报错 SQLSTATE[HY000] [1040] Too many connections。这不是单纯调大 MySQL 参数能解决的,必须从连接生命周期、复用机制和请求调度三方面协同优化。
禁用短连接,强制启用持久连接
TP6 默认使用短连接(每次请求新建、结束后释放),一万并发 ≈ 一万新连接同时涌向 MySQL,极易打满连接池。应主动开启 PDO 持久连接,复用底层 TCP 连接:
- 在
config/database.php的数据库配置中加入:'params' => [\PDO::ATTR_PERSISTENT => true] - 配套调整 MySQL 服务端:
设置wait_timeout = 300(避免空闲连接长期占用)
设置max_connections ≥ 200(建议 256~512,视服务器内存而定) - 注意:持久连接不等于连接池,它只是复用进程内连接;需配合 PHP-FPM worker 复用才能真正减少建连压力
收紧 PHP-FPM 并发承载能力
一万并发不等于需要一万 PHP 进程——那会直接压垮内存和数据库。应通过 FPM 配置让有限 worker 承载更高吞吐:
- 设
pm.max_children = 64(或 96,根据内存测算:每个 worker 约占 20–30MB) - 启用
pm = ondemand或pm = dynamic,避免空闲进程占资源 - 设
pm.process_idle_timeout = 10s,快速回收空闲 worker - 关键:确认
pm.max_requests = 1000(防止长运行后内存泄漏),但不要设为 0
显式控制连接获取与释放时机
TP6 不自动管理连接释放,尤其在异常、重定向或提前 return 场景下容易“漏关”。需主动干预:
立即学习“PHP免费学习笔记(深入)”;
- 避免在控制器中多处调用
Db::table()——每次都会尝试拿新连接;改用单次$db = Db::connect(); $db->table(...)显式持有 - 事务务必配对:
try { Db::startTrans(); ... Db::commit(); } catch { Db::rollback(); },否则连接被事务锁住不释放 - 慎用
Db::query('SELECT 1')健康探测——它本身也建连接;改用 FPM + MySQL 的tcp_check或中间件心跳更轻量
补充防御:加连接获取超时与降级兜底
即使做了以上优化,极端场景仍可能因网络抖动或 MySQL 瞬间卡顿导致连接阻塞。需设置明确等待边界:
- 仅限 TP6.1+ + think-orm v3.0+:在连接配置中启用连接池并设
'pool' => ['get_timeout' => 800](单位毫秒) - 搭配
break_reconnect => true,主库不可用时快速切从库(若已配读写分离) - 核心接口增加缓存层(Redis),命中缓存则跳过 DB 查询;key 必须带业务前缀+过期时间,防雪崩
- 非核心操作(如日志记录、通知)异步化,走消息队列,彻底剥离 DB 压力



















