Laravel 4.2升级至5.5+PHP切换后MySQL 5.6过载求助
解决Laravel 5.5 + PHP 7.2升级后MySQL线程暴增的问题
我之前帮好几个团队处理过类似的版本升级后MySQL负载崩盘的情况,你的问题其实挺典型的,大概率是框架、PHP版本变化带来的查询行为或连接管理差异导致的,给你列几个排查方向和解决办法:
1. 先排查Laravel查询逻辑的变化
从Laravel 4.2到5.5,Eloquent和查询构建器的默认行为有不少改动,很容易触发N+1查询暴增:
- 旧版本里某些延迟加载的关联,可能因为框架默认配置或代码写法的兼容问题,在5.5里变成了即时加载;或者你在升级时没注意到
with()方法的使用差异,导致每个请求都多执行了几十上百条SQL。 - 临时开启查询日志排查:在代码里加
DB::enableQueryLog(),然后用dd(DB::getQueryLog())输出当前请求的所有SQL,对比旧环境相同请求的查询数量,很快就能发现有没有异常的重复查询。
2. 检查PHP-FPM与MySQL的连接匹配
PHP 7.2用的mysqlnd驱动和PHP 5.6的旧驱动在连接处理上有差异,再加上FPM进程数配置不当,会直接把MySQL连接池撑爆:
- 先看PHP-FPM的
pm.max_children设置:如果新环境这个值比旧环境大很多,比如旧环境是32,新环境设成了100+,每个FPM进程都会持有一个MySQL连接,瞬间就会超过MySQL的max_connections,导致大量线程排队等待连接,最终过载。先把这个值降到和旧环境一致,观察MySQL线程数会不会回落。 - 确认MySQL的
wait_timeout和interactive_timeout参数:如果新环境这两个值设得太大,闲置的连接不会被及时回收,也会占用连接数。
3. 排查MySQL配置的隐性差异
哪怕你说配置一致,有些细节参数很容易被忽略:
- InnoDB缓冲池大小:
innodb_buffer_pool_size是MySQL性能的核心参数,如果新环境用了默认值(比如只有几十M),而旧环境调大到了内存的70%-80%,会导致缓存命中率暴跌,大量请求直接读磁盘,MySQL不得不开更多线程处理,最终宕机。可以用这个命令计算命中率:
正常命中率应该在99%以上,如果远低于这个值,立刻调大SELECT (1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)) * 100 AS buffer_pool_hit_rate FROM information_schema.GLOBAL_STATUS;innodb_buffer_pool_size。 - 线程缓存:
thread_cache_size如果太小,MySQL每次处理新请求都要创建新线程,而不是复用闲置线程,也会导致线程数快速飙升。旧环境可能已经调大了这个值,新环境没同步的话就会出问题。
4. 代码层面的兼容性坑
PHP 7.2对旧语法的兼容性有变化,可能导致某些Laravel 4.2的代码在新环境下出现异常:
- 比如某些模型的访问器、事件监听器,在PHP 7.2下触发了无限递归或循环查询;或者旧的扩展包在新环境下有bug,导致额外的数据库请求。可以尝试临时禁用非核心的业务模块,逐步排查哪个模块导致的连接暴增。
- 另外,Laravel 5.5的队列系统默认配置和4.2不同,如果升级后用了数据库队列但没启动消费者,任务会堆积在数据库里,每个请求都要插入任务记录,也会增加数据库负载。
紧急恢复步骤
如果服务器现在还在宕机状态,可以先做这两步快速止损:
- 降低PHP-FPM的
pm.max_children到旧环境的水平,重启FPM; - 临时调大MySQL的
max_connections(别太大,比如设成300),同时开启慢查询日志(long_query_time=1),定位慢查询或重复查询。
内容的提问来源于stack exchange,提问作者Lucas Mousinho
相关产品推荐
相关产品推荐

