生产环境不建议直接在 Laravel 应用层开启全量慢查询日志,优先使用数据库自带的慢查询日志功能。如果必须使用应用层日志,需改为异步通道并设置合理阈值,避免同步写盘阻塞请求。
先说结论:Laravel 应用层记录慢查询属于同步 I/O 操作,高并发下会显著增加请求耗时,生产环境应优先启用 MySQL 原生慢查询日志。
- 先定位:确认日志是写在应用层文件还是数据库层,检查是否阻塞主线程
- 先做:关闭应用层查询监听,改用数据库原生慢查询日志或 APM 工具
- 再验证:观察接口平均响应时间和服务器 I/O 等待率是否回落
命令速用版
# 检查 MySQL 慢查询日志状态
mysql -u root -p -e "SHOW VARIABLES LIKE 'slow_query_log';"
# 临时开启 MySQL 慢查询日志(无需重启)
mysql -u root -p -e "SET GLOBAL slow_query_log = 'ON';"
# 查看 Laravel 日志文件实时增长情况
tail -f storage/logs/laravel.log
为什么会这样
Laravel 应用层记录查询日志默认在主线程同步执行,每次数据库请求完成后都会触发写文件操作。
在高并发场景下,频繁的磁盘 I/O 会阻塞 PHP 进程,导致请求排队。数据库原生的慢查询日志由数据库进程异步写入,对应用性能影响较小。
分步处理
步骤 1:确认日志实现方式
检查 `app/Providers/AppServiceProvider.php` 的 `boot` 方法中是否有 `DB::listen` 代码。如果有,这段代码会在每个查询结束后执行,包含日志写入逻辑。
步骤 2:关闭应用层查询监听
在生产环境配置中注释掉 `DB::listen` 相关代码,或增加环境判断仅在本地生效。
// 修改前
DB::listen(function ($query) { ... });
// 修改后
if (app()->environment('local')) {
DB::listen(function ($query) { ... });
}
步骤 3:启用数据库原生慢查询
修改 MySQL 配置文件 `my.cnf` 或通过命令设置 `slow_query_log` 为 ON,设置 `long_query_time` 阈值(例如 1 秒)。
步骤 4:引入异步日志或 APM(可选)
如果必须保留应用层日志,配置 Monolog 使用异步处理器,或接入 SkyWalking、Pinpoint 等 APM 工具进行性能监控。
怎么验证是否生效
观察 Laravel 日志文件 `storage/logs/laravel.log` 是否停止增长。使用压测工具或监控面板查看接口平均响应时间(RT)是否下降。检查服务器 `iostat` 命令输出,确认 I/O 等待率降低。
常见坑
1. 日志文件未轮转:慢查询日志可能快速增长占满磁盘,需配置 logrotate。
2. 阈值设置过低:将正常查询误判为慢查询,导致日志量过大。
3. 权限问题:MySQL 慢查询日志文件路径需确保 mysql 用户有写入权限。
常见问题
Laravel 自带慢查询日志配置吗?
Laravel 框架本身没有直接的慢查询日志配置项,通常通过 `DB::listen` 事件监听实现。
生产环境能用 Telescope 监控查询吗?
不建议,Telescope 设计用于调试环境,生产环境开启会消耗大量资源且存在安全风险。
异步日志能完全消除性能影响吗?
不能,异步日志仅减少阻塞时间,仍会消耗 CPU 和 I/O 资源,优先推荐数据库原生日志。
参考来源
Laravel Documentation - Database: Query Logging
MySQL Documentation - The Slow Query Log