MySQL 持久连接(pconnect)在 ThinkPHP 中拖慢高并发,因 PHP-FPM worker 复用导致每个进程独占持久连接不释放,撑爆 MySQL max_connections;应禁用 pconnect,调低 wait_timeout,改用短连接+外部连接池。

为什么 mysql_pconnect 在 ThinkPHP 里反而拖慢高并发?
ThinkPHP 默认不启用持久连接,但有人手动在配置里加 'pconnect' => true,结果 QPS 不升反降,甚至出现大量 Too many connections。根本原因不是数据库没能力,而是 PHP-FPM 进程复用导致连接池失控:每个 worker 持有独立的持久连接,进程不销毁,连接就不释放,最终撑爆 MySQL 的 max_connections。
实操建议:
- 禁用
pconnect,改用短连接 + 连接复用中间件(如 PDO 的PDO::ATTR_PERSISTENT => false) - 把 MySQL 的
wait_timeout从默认 28800 秒调低到 60–120 秒,避免空闲连接长期占位 - 监控
SHOW STATUS LIKE 'Threads_connected',持续高于 80%max_connections就要干预
负载均衡下 Session 和数据库写操作不一致怎么办?
用 Nginx 做轮询,用户 A 的请求打到服务器 1 写了订单,下一秒读请求打到服务器 2,却查不到刚写的记录——这不是缓存没刷,是主从延迟或读写分离没兜住。
关键不是“要不要读写分离”,而是“哪些操作必须走主库”:
- 所有
INSERT/UPDATE/DELETE后紧跟SELECT的场景(比如创建后立刻查详情),强制走主库,ThinkPHP 可用Db::master()->table(...) - 登录态、购物车等强一致性数据,Session 存 Redis 而非文件,且 Redis 需单节点或开启强一致模式(如 Redis Cluster 的
readonly关闭) - 避免在事务中混用主从,ThinkPHP 的
Db::transaction()默认全程走主库,这点不用改,但别在外层手动切从库
ThinkPHP 自带的数据库连接池真的存在吗?
没有。ThinkPHP 5.1+ 的 think\db\Connection 是单例 + 懒连接,每次 Db::table() 都会检查连接是否活跃,不活跃就重连,但它不管理连接数量、不复用空闲连接、也不限制并发建连——本质上仍是“用完即断”,不是连接池。
真要控连接数,得靠外部手段:
- 在 PHP-FPM 层限流:
pm.max_children别设过高,配合pm.start_servers稳定值,避免瞬间拉起几百个进程抢连 - MySQL 侧做连接级限速:
GRANT ... WITH MAX_CONNECTIONS_PER_HOUR 100给应用账号 - 用 Swoole 或 RoadRunner 替换 PHP-FPM,它们自带协程连接池,ThinkPHP 可通过
think-swoole扩展对接
Redis 作二级缓存时,缓存击穿让 DB 直接被打挂?
促销页面查商品,缓存失效瞬间上百请求穿透到 DB,而 ThinkPHP 的 Cache::get() 默认不带互斥锁,多个进程同时发现缓存为空,就一起重建——这就是缓存雪崩的前奏。
简单有效的方式是加一层原子写保护:
- 用 Redis 的
SET key value EX 60 NX(NX 表示仅当 key 不存在时才设),成功者去查 DB 并回填;失败者短暂休眠后重试Cache::get() - ThinkPHP 本身不封装这个逻辑,需手写,别依赖
Cache::remember(),它只做“查缓存→查DB→写缓存”,没防穿透 - 对热点 key,干脆预热:定时任务在低峰期主动
Cache::set(),过期时间加随机偏移(如 3600±300 秒),避免集体失效
复杂点在于主从延迟和缓存更新时机——删缓存那一刻,DB 事务可能还没提交完,所以删操作必须放在事务 提交后,ThinkPHP 的 Db::transaction() 回调里做最稳妥。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










