应通过horizon实时指标、redis llen命令、数据库jobs表三类手段交叉验证高优先级队列积压:horizon查pending数及吞吐下降/耗时上升;redis执行llen queues:high获取瞬时长度;db查jobs表中queue='high'且reserved_at is null的任务数。

高优先级队列(如 high)一旦积压,风控、支付通知等关键任务就会延迟甚至超时失效。不能只靠“看 Horizon 页面有没有红点”,得用三类手段交叉验证:实时指标、底层长度、数据库状态——缺一不可。
Horizon 里怎么看 high 队列是否真积压
Horizon 的 “Pending jobs” 数值有缓存延迟(默认 5 秒刷新),且只反映它自己采样的那一瞬间。光看数字容易误判:
- 如果
queues:high.waiting在 /horizon/api/metrics 接口里持续 ≥ 50,同时jobs_per_minute下降 +avg_duration上升,说明 worker 吞吐已跟不上,不是瞬时抖动 - 点击 high 队列名称进详情页,重点看 “Recent Jobs” 列表里是否有大量
reserved_at为空但available_at是 1 分钟前的任务——这是典型的“卡在队列头却没被取走” - 确认 config/horizon.php 中 supervisor 配置确实包含
'queue' => ['high'],否则 Horizon 根本不监控这个队列,页面上都看不到条目
Redis LLEN 命令查 queues:high 真实长度
Horizon 数据不准?直接读 Redis 键值最可靠。但要注意键名可能被前缀污染:
- 默认键是
queues:high;若设置了HORIZON_PREFIX=prod:,实际键名是prod:queues:high,LLEN查错键会返回 0 -
redis-cli -h 127.0.0.1 -p 6379 LLEN queues:high返回值突增至 100+,且 30 秒内不下降,基本可断定积压 - 别用 crontab 每秒跑一次——Redis 本身不扛高频
LLEN,建议最小间隔设为 20 秒,且加grep -E '^[8-9][0-9]$|^1[0-9]{2,}$'过滤,避免日志刷屏
查 jobs 表里 high 队列的待处理任务数
这个方法只对 database 驱动有效,redis 驱动下 jobs 表是空的。别查错驱动:
- 先确认
QUEUE_CONNECTION=database,否则SELECT COUNT(*) FROM jobs WHERE queue = 'high' AND reserved_at IS NULL永远是 0 - 注意
reserved_at IS NULL才是真正“等待中”的任务;reserved_at不为空的是正在被 worker 处理的,不算积压 - payload 字段是 base64 编码的 JSON,phpMyAdmin 里直接看是乱码;要用
BASE64_DECODE+JSON_DECODE(MySQL 8.0.27+)才能提取job类名和参数,否则无法定位具体是哪个任务拖慢了队列
为什么三个方法都要用,而不是只信一个
因为每个数据源反映的是不同层面的状态:Horizon 是采样指标,Redis LLEN 是瞬时内存快照,jobs 表是持久化记录。比如 Horizon 显示 pending 为 0,但 LLEN queues:high 返回 120——说明 Horizon 进程挂了或没拉到新数据;又比如 jobs 表里 high 队列有 30 条,但 Redis 键不存在——说明你误配了驱动。真实生产环境里,这些矛盾每天都会出现,靠单一入口判断等于蒙眼开车。











