redis队列任务优先级需用多队列+独立进程实现:启动两个queue:work进程分别监听high/low队列,通过--sleep和--max-jobs控制执行节奏;laravel不支持任务级优先级,仅支持队列名维度分流。

Redis 队列里怎么设置任务优先级
原生 Laravel 的 redis 驱动不支持「任务级」优先级(比如给某条 dispatch() 加个 priority=high 参数),它只认「队列名」这个维度。所以真要分优先级,得靠多个队列 + 启动多个 artisan queue:work 进程,并配不同权重。
常见错误现象:php artisan queue:work redis --queue=high,low 看似能混跑,实际是轮询消费,high 队列的任务可能被 low 挤占执行时机,尤其当 low 任务量大时。
- 正确做法:启动两个独立进程,分别监听不同队列,用
--sleep和--max-jobs控制节奏 php artisan queue:work redis --queue=high --sleep=1 --max-jobs=100php artisan queue:work redis --queue=low --sleep=3 --max-jobs=50- 关键点:高优队列的
--sleep要更小(响应快),--max-jobs可设更高(避免频繁重启丢失上下文)
Laravel 配置里怎么定义多个 Redis 队列
不是在 config/queue.php 里新增数组键,而是复用同一个 redis 连接,靠 default 和 connections.redis.queue 控制默认队列名;真正分流靠 dispatch() 时显式指定队列名。
使用场景:发短信(sms)、发邮件(email)、生成报表(report)需要隔离资源和失败影响。
- 配置不用改,默认
connections.redis.queue是default,但你可以在.env里覆盖:QUEUE_CONNECTION=redis,然后代码里用SomeJob::dispatch()->onQueue('sms') - Redis 实际存储的 key 是
queues:sms、queues:email,互不影响 - 注意:别在
config/queue.php里手动加'sms' => [...]—— Laravel 不认这种写法,会报Connection [sms] does not exist
为什么不能靠 Redis ZSET 或自定义延迟队列模拟优先级
有人试过用 ZADD queues:priority 100 job1 手动推任务进有序集合,再写个自定义 Worker 去 ZRANGE 拉取,这理论上可行,但会绕过 Laravel 队列的整个生命周期管理:失败重试(tries)、延迟(delay)、监控(failed_jobs 表)、事件(JobProcessing)全失效。
性能与兼容性影响明显:
- Redis 内存占用不可控:ZSET 的 score 如果用时间戳+优先级拼接,排序逻辑复杂,且无法复用 Laravel 的
retry_after机制 - Horizon 不识别你的 ZSET 结构,所有监控、重试、重播功能归零
- 升级 Laravel 版本时,底层
RedisQueue类行为变化(比如 v10 改了pop的原子性实现),你的自定义逻辑大概率崩
Horizon 下怎么让高优队列获得 CPU 时间保障
Horizon 默认按队列名顺序消费,supervisor 配置里的 balance 策略(simple/auto)只管进程数分配,不管单个进程内队列调度顺序。所以即使你写了 'high' => ['connection' => 'redis', 'queue' => ['high']],如果没调 balance,还是可能卡住。
- 必须在
config/horizon.php的environments下为每个环境单独配supervisors - 给高优队列单独一个 supervisor,设
'minProcesses' => 2,低优队列另起一个,设'minProcesses' => 1 - 关键参数:
'balance' => 'false'(禁用自动均衡),否则 Horizon 会把空闲进程从high拿去补low,违背初衷 - 验证是否生效:看
horizon:supervisors命令输出,确认两个 supervisor 的queues字段互不交叉
最容易被忽略的是 Supervisor 的命名——如果你在配置里写 'name' => 'web',但启动命令是 php artisan horizon --environment=production,而 config/horizon.php 里 environments.production.supervisors 没定义对应项,那所有配置都白搭。











