一、Redis Queue 在 Yii2 中的定位
在 Yii2 中,yii2-queue
是一个统一的队列抽象层 ,它提供了相同的 API,但可以切换不同的驱动(Redis、RabbitMQ、Beanstalk、DB 等)。
Redis Queue 驱动的核心特点是:
- 内存型存储 → 高速(微秒级),但需要注意持久化。
- 发布/订阅 + 列表存储 → 可以同时支持即时推送(listen)和批量处理(run)。
- 无类型限制 → 任务序列化成 JSON 存储,支持任意 PHP 对象(可实现跨 PHP 版本兼容)。
二、Redis Queue 的底层机制
2.1 数据结构
在 Redis 中,队列主要用两个结构:
- List(列表) → 存储任务队列(FIFO)
- Channel(频道) → 用于触发监听器的实时响应
存储示例(假设频道为 queue
):
LPUSH queue:waiting {"id":1,"job":"SendEmailJob",...}
监听模式下,Redis 会通过 BRPOP
阻塞式弹出任务。
2.2 Job 序列化与反序列化
- 推送任务时,
yii2-queue
会将JobInterface
实例序列化为字符串(默认 PHP 序列化)。 - 消费时反序列化,执行
execute()
方法。 - 因此 Job 类必须能被反序列化 (需要
autoload
正确配置)。
2.3 消费模式
-
监听模式 (
queue/listen
)- Redis 阻塞等待新任务(
BRPOP
),实时执行。 - 适合实时任务(通知、推送)。
- Redis 阻塞等待新任务(
-
循环模式 (
queue/run
)- 依次取出任务执行,结束后退出。
- 常配合
crontab
,适合低频批处理任务。
三、Yii2 Redis Queue 高级用法
3.1 任务优先级
Redis Queue 没有内置优先级,但可以通过多个频道模拟:
php
Yii::$app->queueHigh->push(new HighPriorityJob());
Yii::$app->queueLow->push(new LowPriorityJob());
消费者按优先顺序监听多个队列。
3.2 延迟任务
内部通过 Redis 的 ZSET + 轮询 实现延迟:
php
Yii::$app->queue->delay(300)->push(new ReportJob());
表示 300 秒后执行。
3.3 定时任务(伪 Cron)
可以结合延迟任务 + 循环推送实现:
php
if (time() % 60 === 0) {
Yii::$app->queue->push(new SyncDataJob());
}
或者直接用系统 cron
触发。
3.4 失败重试与死信队列
开启 attempts
:
php
'queue' => [
'attempts' => 3, // 自动重试 3 次
],
可配合 EVENT_AFTER_ERROR
记录死信任务:
php
Yii::$app->queue->on(\yii\queue\Queue::EVENT_AFTER_ERROR, function ($event) {
Yii::error("任务失败: " . json_encode($event->job));
});
四、生产环境最佳实践
4.1 独立消费进程
用 supervisord
或 systemd
保证 php yii queue/listen
永远运行:
ini
[program:yii-queue]
command=php /var/www/yii queue/listen
autostart=true
autorestart=true
numprocs=2
stdout_logfile=/var/log/yii-queue.log
4.2 队列监控
- 长度监控 :
LLEN queue:waiting
- 失败任务统计:记录到 MySQL 或 Elasticsearch
- Prometheus 指标:采集队列长度、任务耗时
4.3 Redis 持久化
生产建议开启:
- AOF(Append Only File):防止宕机数据丢失
- RDB 快照:减少恢复时间
4.4 并发优化
- 多进程消费 :
supervisord
numprocs > 1 - 任务拆分:大任务拆成多个小任务,提高吞吐
- 批量处理:一个 Job 处理多条数据,减少 Redis 交互
五、常见坑与排查
-
Job 类找不到
- 确保
composer autoload
正确,类文件可被反序列化。
- 确保
-
任务卡住
- 检查 Redis 队列长度
LLEN
- 查看消费者进程是否退出
- 检查 Redis 队列长度
-
内存泄漏
- 长时间运行的进程注意释放大对象、避免缓存堆积
-
延迟任务不执行
- 延迟任务依赖监听进程扫描定时队列,确保
queue/listen
运行
- 延迟任务依赖监听进程扫描定时队列,确保
六、完整示例
Job 类
php
namespace app\jobs;
use yii\queue\JobInterface;
class SendEmailJob implements JobInterface
{
public $email;
public function execute($queue)
{
mail($this->email, 'Hello', 'Welcome!');
}
}
推送任务
php
Yii::$app->queue->push(new \app\jobs\SendEmailJob([
'email' => 'test@example.com'
]));
消费任务
bash
php yii queue/listen
