首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 使用 php-resque + Redis 實現消息佇列:從原理到落地完整教程

     編輯:PHP 相關知識

PHP 使用 php-resque + Redis 實現消息佇列:從原理到落地完整教程

Web 應用中耗時任務(發郵件、生成報表、推播通知)不宜阻塞 HTTP 請求。Resque 架構(Job + Queue + Worker)提供標準化解決方案。本文詳細講解 php-resque 安裝、Job/Worker 編寫、佇列操作、狀態追蹤與生產部署要點。

一、核心角色劃分

角色職責實現形式
Job(任務)具體業務邏輯(如發送郵件)一個 PHP Class,必須實現 perform() 方法
Queue(佇列)任務緩衝區,先進先出Redis List(LPUSH/RPOP)
Worker(工作者)常駐進程,消費佇列並執行 JobPHP CLI 腳本,支援多進程、多佇列、fork 子進程

二、環境需求與安裝

  • Linux 環境(需 pcntl、posix 擴充,Windows 不支援 fork)。
  • Redis Server(apt-get install redis-server)。
  • Composer 管理依賴。
# 專案目錄
composer require chrisboulton/php-resque
# 或手動 clone
git clone https://github.com/chrisboulton/php-resque.git
cd php-resque && composer install

三、編寫 Job 類別

// jobs/SendMailJob.php
class SendMailJob {
    public function perform() {
        // $this->args 為入佇列時傳遞的參數陣列
        $to      = $this->args['to'];
        $subject = $this->args['subject'];
        $body    = $this->args['body'];

        // 實際發送邏輯(可用 PHPMailer)
        $mailer = new \PHPMailer\PHPMailer\PHPMailer();
        // ... 設定 SMTP、內容 ...
        $mailer->addAddress($to);
        $mailer->Subject = $subject;
        $mailer->Body = $body;
        $mailer->send();

        // 可選:輸出日誌到 STDOUT,Worker 會捕獲
        fwrite(STDOUT, "[".date('Y-m-d H:i:s')."] Mail sent to {$to}\n");
    }
    
    // 可選:設置失敗重試次數
    // public $maxRetries = 3;
    
    // 可選:設置佇列名稱(預設 default)
    // public $queue = 'emails';
}

四、將 Job 推入佇列(生產端,如 Controller)

require_once 'vendor/autoload.php';

use Resque\Resque;

Resque::setBackend('127.0.0.1:6379'); // Redis 連線

$jobId = Resque::enqueue('emails', 'SendMailJob', [
    'to'      => 'user@example.com',
    'subject' => '歡迎註冊',
    'body'    => '感謝您的註冊,您的驗證碼是 123456',
], true); // true = 追蹤狀態

echo "Job 已入佇列,ID: {$jobId}";

五、啟動 Worker(消費端,命令列常駐)

# 單進程處理 emails 佇列
QUEUE=emails php vendor/bin/resque.php

# 多進程(需安裝 php-resque-scheduler 或使用 supervisor 管理多個 worker)
COUNT=5 QUEUE=emails php vendor/bin/resque.php

# 處理所有佇列
QUEUE=* php vendor/bin/resque.php

Worker 會 fork 子進程執行 Job,主進程負責監控與信號處理。生產環境**必須使用 Supervisor/Systemd 管理 Worker 進程**,保證自動重啟、日誌輪轉、開機自啟。

六、Supervisor 部署範例

# /etc/supervisor/conf.d/resque-worker.conf
[program:resque-worker]
command=php /var/www/project/vendor/bin/resque.php
process_name=%(program_name)s_%(process_num)02d
numprocs=5
directory=/var/www/project
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/resque-worker.log
environment=QUEUE="emails",APP_ENV="production"
supervisorctl reread && supervisorctl update && supervisorctl status

七、狀態追蹤與監控

// 獲取 Job 狀態
$status = Resque\Job\Status::get($jobId);
echo $status; // 1=waiting, 2=running, 3=failed, 4=complete

// 失敗任務查看
$failed = Resque\Failure\Failure::all(0, 20);
foreach ($failed as $job) {
    echo "Job: {$job['payload']['class']}, Error: {$job['error']}\n";
}

// 重試失敗任務
Resque\Failure\Failure::retry($failedJobId);

八、進階功能與最佳實踐

  • 延遲任務: 使用 php-resque-scheduler 擴充,支援 enqueueAt($timestamp, ...)、enqueueIn($seconds, ...)。
  • 優先級佇列: 啟動 Worker 時指定 QUEUE=high,default,low,高優先級佇列先被消費。
  • Job 內部異常處理: perform() 拋出異常會被 Worker 捕獲、標記失敗、記錄堆疊、可選重試。
  • 唯一性鎖: 避免重複任務,可在 perform() 開頭用 Redis SETNX 鎖定 key。
  • 監控儀表板: 部署 php-resque-web(Sinatra/React 介面)即時查看佇列長度、Worker 狀態、失敗率。

九、常見坑點避雷

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題解決
Worker 頻繁崩潰檢查 PHP memory_limit、Job 記憶體洩漏、Redis 連線超時重試
任務卡住不執行確認 Worker 啟動的 QUEUE 參數與 enqueue 的佇列名一致
重複執行Job 內加冪等性 Key(Redis SETNX),或資料庫唯一索引
中文亂碼確保 PHP 檔案 UTF-8、Redis 連線無編碼轉換、JSON 編碼加 JSON_UNESCAPED_UNICODE