高并发下应通过异步队列剥离日志写入:选用Redis驱动、自定义AsyncLogHandler分发任务、精简日志内容、专用队列消费并优化存储。

高并发下同步写日志会拖慢响应,核心解法是把日志写入从请求主流程中剥离——用队列异步处理,再配合驱动、处理器和存储层的针对性优化。
选对队列驱动:Redis 是生产首选
database 驱动在 50+ QPS 下容易因轮询和行锁导致延迟;Redis 具备原子出队、低延迟特性,更适合高并发日志投递。
- 在 .env 中设:
QUEUE_CONNECTION=redis,并确保REDIS_CLIENT=predis或phpredis已安装 - 检查 config/queue.php 中 redis 连接配置是否指向可用的 Redis 实例(host/port/password)
- 为日志任务单独建队列,比如
'queue' => 'logs',避免与邮件、导出等任务争抢资源
自定义异步日志处理器
不能直接用 Laravel 默认的 daily 或 stack 通道,需基于 Monolog 扩展一个能发队列任务的 Handler。
- 新建 app/Logging/Handlers/AsyncLogHandler.php,继承
AbstractProcessingHandler -
write()方法里不写文件,而是分发日志 Job:ProcessLog::dispatch($level, $message, $context)->onQueue('logs') - 在 config/logging.php 的 channels 数组中注册该 handler,例如命名为
'async'
精简日志内容与格式
每条日志越轻量,队列消费越快,数据库压力越小。
- 禁用 formatter 中的动态调用,如
Request::ip()、Request::fullUrl()—— 它们重建请求上下文,开销堪比一次简单查询 - 时间格式用
'Y-m-d H:i:s'而非'c',省去时区转换计算 - 静态字段(如 app name、hostname)用
static属性缓存,避免每次 new 实例都重复获取 - 若用 Activitylog,启用
logOnlyDirty()和logOnly(['field1', 'field2']),跳过无变化字段和非关键字段
队列消费与存储协同优化
光投递快不够,消费端也要稳且高效。
- 用 Supervisor 管理
queue:work进程,设置--queue=logs专用监听,防止被其他队列干扰 - 日志 Job 的
handle()方法里,使用Log::driver('single')或'daily'写入,但务必关掉'lock' => false和设好'max_files' => 30 - 考虑将日志表迁到独立数据库连接(如
'connection' => 'logs_db'),减轻主库 I/O 压力 - 为日志表常用查询字段加索引:
created_at、causer_id、log_name


















