吞吐量图表不更新是因为horizon:snapshot命令未定时执行,需检查Laravel Scheduler配置、服务器cron、Redis连接及config/horizon.php中enabled设置是否正确。

Horizon 的吞吐量图表不是“实时秒级刷新”的仪表盘,它依赖 horizon:snapshot 命令定时采集,不配调度器就永远不动。
为什么吞吐量图表一直不更新?
这不是 Horizon 本身坏了,而是指标采集链断了。吞吐量(TPM、avg_duration 等)由 horizon:snapshot 命令驱动,它每分钟把 Redis 中的计数器快照存入 Horizon 自己的 Redis 结构里,Web 页面再拉取这些快照数据绘图。
- 没启用 Laravel Scheduler:检查
app/Console/Kernel.php中的schedule()方法是否注册了$schedule->command('horizon:snapshot')->everyMinute(); - Scheduler 没真正运行:确认服务器上 cron 是否在每分钟执行
php /path/to/artisan schedule:run,且路径和 PHP CLI 版本与 Web 一致 - Redis 连接超时或慢:手动运行
php artisan horizon:snapshot,如果卡住或报Connection timed out,说明 Horizon 进程和 Web 请求共用的 Redis 连接池已争抢激烈,需调大redis.connections.default.pool.size - 生产环境未放开路由:
config/horizon.php中'enabled' => true必须显式设置,且Horizon::auth()回调不能返回false
吞吐量下降时怎么快速定位瓶颈?
别只盯着图表数字掉,要交叉看三层状态:Horizon 页面指标 + Redis 键长度 + Worker 实际进程数。
- 先看 Horizon 页面右上角 “Processes” 和 “Processing” 数值:如果 Processes 是 10,但 Processing 长期 ≤ 2,说明大部分 Worker 没干活——大概率是任务阻塞(如
sleep()、同步 HTTP 请求)或 Redis 拉取失败 - 执行
redis-cli llen queues:default(把default换成你实际队列名):如果返回值持续 > 50,而 Horizon 显示 “Pending jobs” 却只有个位数,说明horizon:snapshot采集异常或 Redis 键前缀被污染(检查config/database.php中 Redisprefix是否与 Horizon 配置一致) - 执行
ps aux | grep 'horizon:work' | grep -v grep:数出真实运行的php artisan horizon:work进程数,对比config/horizon.php中该 Supervisor 的maxProcesses——若远小于配置值,说明 Supervisor 启动失败或被系统 OOM Kill
TPM 波动大,是正常还是危险?
TPM(Tasks Per Minute)本身波动很正常,关键看波动伴随什么现象:
- TPM 突降 + avg_duration 突升:典型 CPU 或 I/O 瓶颈,比如任务里用了
file_get_contents()加载大文件,或数据库查询没加索引导致锁表 - TPM 稳定但 avg_duration 持续缓慢爬升:内存泄漏迹象,尤其出现在长时间运行的 Worker 进程中(PHP-FPM 不适用,CLI Worker 才会累积)
- TPM 隔几分钟规律性归零:可能是
max_execution_time触发强制终止,Worker 异常退出后由 Supervisor 重启,造成周期性中断;检查php --ini输出的 CLI 模式max_execution_time值 - TPM 与 waiting 数同步上涨:说明新任务涌入速度 > 处理速度,不是代码问题,而是资源不足——该加 Worker 进程,或拆分高耗时任务
吞吐量背后没有魔法,它只是 Redis 计数器 + 定时快照 + Web 渲染的组合。最容易被忽略的是:所有指标都基于同一套 Redis 连接,一旦这个连接慢或不稳定,整个监控链就失真——所以调优永远从 Redis 连接池开始,而不是改 Horizon 配置。


















