核心问题是日志同步写文件阻塞请求链路,导致高并发下i/o和文件描述符瓶颈;应立即停用同步日志、关闭调试模式,长效采用redis队列异步写入,并分级控制日志内容与存储,配套系统层加固资源限制。

ThinkPHP6 一万并发下日志导致卡顿,核心问题不是“日志多”,而是默认同步写文件阻塞了整个请求链路。每条 Log::write() 都要 fopen → fwrite → fflush → fclose,QPS 上千时磁盘 I/O 和文件描述符迅速成为瓶颈,接口响应直接拖到几秒甚至超时。
立即止血:停用同步日志写入
别改业务代码,先切掉日志对主线程的绑定:
- 在
config/log.php中,把默认file驱动替换为自定义异步驱动,或直接设'default' => 'null'(临时关闭) - 确认
APP_DEBUG = false,关闭调试模式下的 SQL 日志、变量 dump 等高频输出 - 检查是否误开了
log.level = 'debug',生产环境只保留info、warning、error
长效方案:用 think-queue 接管日志写入
让 Log::write() 只负责发任务,不落地:
- 队列驱动必须用 Redis(避免 MySQL 表锁影响吞吐),配置
queue.default = 'redis' - 消费者进程单独启动:
php think queue:listen --queue=log --delay=0 --memory=128 --tries=3 - 消费者内直接调用
file_put_contents($path, $logLine, FILE_APPEND | LOCK_EX),不走 Log 类 - 每条日志必须携带完整上下文:请求 ID、用户 UID、trace_id、时间戳,否则异步后无法关联排查
日志内容与存储分级控制
不是所有日志都值得异步记录,得做取舍:
- Web 请求日志走专用
channel('web'),只记info(成功)、error(5xx),禁用debug - 定时任务日志强制重定向到独立文件:
php think cron:job >> runtime/log/cron/`date +\%Y\%m\%d`.log 2>&1 - 队列消费日志加字段:
['job' => 'SendMailJob', 'pid' => getmypid(), 'queue' => 'mail'] - 错误日志必须结构化:包含类名、数据 ID、堆栈前 200 字符,拒绝 “执行失败” 这类无意义记录
配套系统层加固
光改 PHP 不够,底层资源也得跟上:
- 调高系统文件描述符限制:
ulimit -n 65535,并在/etc/security/limits.conf中固化 - PHP-FPM 配置
rlimit_files = 65535,防止子进程被掐断句柄 - Nginx 关闭
log_format中的$request_body或大参数,避免 access.log 自身膨胀 - 用
logrotate每日切分 + 压缩,保留最近 7 天,防止磁盘打满
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











