Yii2 Redis Queue

一、Redis Queue 在 Yii2 中的定位

在 Yii2 中,yii2-queue 是一个统一的队列抽象层 ,它提供了相同的 API,但可以切换不同的驱动(Redis、RabbitMQ、Beanstalk、DB 等)。

Redis Queue 驱动的核心特点是:

  1. 内存型存储 → 高速(微秒级),但需要注意持久化。
  2. 发布/订阅 + 列表存储 → 可以同时支持即时推送(listen)和批量处理(run)。
  3. 无类型限制 → 任务序列化成 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 消费模式

  1. 监听模式 (queue/listen)

    • Redis 阻塞等待新任务(BRPOP),实时执行。
    • 适合实时任务(通知、推送)。
  2. 循环模式 (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 独立消费进程

supervisordsystemd 保证 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 交互

五、常见坑与排查

  1. Job 类找不到

    • 确保 composer autoload 正确,类文件可被反序列化。
  2. 任务卡住

    • 检查 Redis 队列长度 LLEN
    • 查看消费者进程是否退出
  3. 内存泄漏

    • 长时间运行的进程注意释放大对象、避免缓存堆积
  4. 延迟任务不执行

    • 延迟任务依赖监听进程扫描定时队列,确保 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