php隊列使用之php-resque

1. 隊列使用場景

1.1. 允許延后|異步|并行處理 (相對于傳統(tǒng)的 即時|同步|串行 的執(zhí)行方式)

  1. 允許延后:搶購活動時绒极,先快速緩沖有限的參與人數(shù)到消息隊列赴肚,后續(xù)再排隊處理實際的搶購業(yè)務(wù)届氢;
  2. 允許異步:業(yè)務(wù)處理過程中的郵件乖菱,短信等通知
  3. 允許并行:用戶支付成功之后助币,郵件通知静陈,微信通知燕雁,短信通知可以由多個不同的消費者并行執(zhí)行榆鼠,通知到達的時間不要求先后順序挤庇。

1.2. 允許失敗和重試

  1. 強一致性的業(yè)務(wù)放入核心流程處理
  2. 無一致性要求或最終一致即可的業(yè)務(wù)放入隊列處理

2. php-resque介紹

php-resque 是輕量級后臺任務(wù)系統(tǒng),基于Redis俭缓,功能設(shè)計簡單刑赶,配置靈活捏浊。相比MQ系統(tǒng)大而全的MQ系統(tǒng),這個顯得小而美

3. php-resque 角色劃分

  1. Job 定義任務(wù)撞叨,是負責具體的業(yè)務(wù)邏輯金踪。
  2. Queue 隊列浊洞,負責Job存/取
  3. Worker 從Queue中取Job來執(zhí)行。 一般為PHP CLI模式下胡岔,后臺守護方式運行法希。

4. 場景使用示例

4.1. 場景業(yè)務(wù)介紹

定點開放約車業(yè)務(wù)場景中,一般會因為流量過大,導(dǎo)致流量暴增靶瘸,應(yīng)用掛掉铁材。為解決這個問題,一般需要在應(yīng)用前端加入消息隊列奕锌,使任務(wù)逐個執(zhí)行著觉。

4.2. 隊列使用流程圖

隊列使用流程.png

4.3. 環(huán)境

  1. php 5.6
  2. thinkphp 3.2.3
  3. redis 3.2

5. 重要代碼示例

5.1.1. 項目目錄結(jié)構(gòu)示例1

項目結(jié)構(gòu)示例.png
項目結(jié)構(gòu)示例.png

5.1. 核心代碼示例

5.1.1. Redis配置

php示例代碼: config.php

'QUEUE' => array(
        'type' => 'redis',
        'host' => '127.0.0.1',
        'port' =>  '6379',
        'prefix' => 'queues',
        'auth' =>  '',
    ),

5.1.2. 隊列單入口配置

php示例代碼: resque

#!/usr/bin/env php
<?php
ini_set('display_errors', true);
error_reporting(E_ERROR);
define('APP_PATH','./Application/');
define('MODE_NAME', 'cli');
define('BIND_MODULE', 'Home');
define('BIND_CONTROLLER', 'Queue');
define('BIND_ACTION', 'index');
$act = $argv[1] ? $argv[1] : 'start';
putenv("Q_ACTION={$act}");
putenv("Q_ARGV=" . json_encode($argv));
require './ThinkPHP/ThinkPHP.php';

5.1.3. 生產(chǎn)者發(fā)送請求入隊核心

php示例代碼 : IndexController.class.php

<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends BaseController {
    /**
     * [Joinbook 請求約車接口]
     *  1.客戶端APP發(fā)送業(yè)務(wù)請求
     *  2.該接口簡單校驗加入任務(wù)隊列
     *  3.入隊成功返回入隊成功標識 jobId
     */
    public function Joinbook()
    {
        $rid = I('rid',32); // 業(yè)務(wù)邏輯參數(shù)
        $subject = I('subject',24); // 業(yè)務(wù)邏輯參數(shù)
        $student_id = I('student_id',343820); // 業(yè)務(wù)邏輯參數(shù)
        try{
            if(empty($rid)|| empty($subject))
                return $this->_return(0,"參數(shù)有誤");
            $args = array(
                'student_id'=>$student_id , 
                'rid'=>$rid ,
                'subject'=>$subject,
                'date'=>date('Y-m-d')
            );
            // 緩存key
            $key = "requse".md5(json_encode($args));
            $yueyue = S($key);
            if($yueyue){
                $this->ajaxReturn(['排隊中,請稍后']);
            }
            $jobId = \Resque::enqueue('default', \Common\Job\Job::Booktrain, $args, true);
            // 入隊成功標識,客戶端使用此標識定時請求,隊列狀態(tài)查詢接口
            $args['jobId'] = $jobId;
            S($key,$args ,5); // 60秒內(nèi)禁止重復(fù)預(yù)約
            $this->ajaxReturn(['msg'=>'入隊,預(yù)約成功','data'=>$args]);
        }catch (\Exception $e){
            $this->ajaxReturn(['異常']);
        }
    }
    //隊列狀態(tài)查詢接口
    public function JoinStatus()
    {
        $jobid = I("jobid");
        $status = new \Resque\Job\Status($jobid);
        //執(zhí)行完成告訴用戶是否成功
        if (!$status->isTracking()) {
            $this->_return(0,"不存在的排隊");
        }else{
            // 緩存key
            $jobid = "Applet\Controller\V2\BooktrainControllerJoinbook_job".$jobid;
            $info = S($jobid);
            //隊列沒執(zhí)行
            if(!$info){
                $info = [];
                $info['msg'] = "等待中...";
                $info['status'] =   100; // 收到該結(jié)果 前端繼續(xù)輪詢,一般限制次數(shù)輪詢
                $this->ajaxReturn($info);
            }
            $this->ajaxReturn($info);  
        }
    }
}

5.1.4. 消費者核心代碼

php示例代碼 : BooktrainJob.php

<?php
namespace Common\Job;
class BooktrainJob
{
    public function perform()
    {
        $args = $this->args;
        $rid = $args['rid'];
        $subject = $args['subject'];
        $args = array(
            'student_id'=>$args['student_id'] , 
            'rid'=>$rid ,
            'subject'=>$subject
        );
        // 數(shù)據(jù)庫業(yè)務(wù)邏輯處理-start
        // $deal_info = D('User')->deal($args);
        $deal_info=[];
        $status =$deal_info['status']?:'200';
        $msg =$deal_info['msg']?:'預(yù)約成功';
        // 數(shù)據(jù)庫業(yè)務(wù)邏輯處理-end
        $margs = array(
            'student_id'=>$args['student_id'] , 
            'rid'=>$args['rid'] ,
            'subject'=>$args['subject'],
            'date'=>date('Y-m-d')
        );
        // 終端打印參數(shù)
        fwrite(STDOUT,json_encode($args)."\n");

        // 獲取當前業(yè)務(wù)的緩存參數(shù),app請求入隊時寫入
        $key = "requse".md5(json_encode($margs)); 
        $result = S($key);

        //將業(yè)務(wù)邏輯處理結(jié)果
        $result["status"] = $status;
        $result["msg"] = $msg;

        // 將參數(shù)及約車結(jié)果放入緩存
        S($key,$result ,1200); 
        
        // 將約車的結(jié)果以工作任務(wù)標識 jobID為key放入緩存,等待客戶端輪詢獲取
        $jobid = "Applet\Controller\V2\BooktrainControllerJoinbook_job".$result['jobId'];
        S($jobid,$result ,300);
    }
}

5.1.5. 命令詳解

# 進入項目目錄
cd /var/www/html/

# 啟動隊列
# --queue=default 啟動隊列的名稱  default(隊列名稱)
# --debug=1  啰嗦模式啟動,會打印詳細調(diào)試信息
# --interval=2 在隊列中循環(huán)的間隔時間,即完成一個任務(wù)后的等待時間惊暴,默認是5秒
# --count=5 需要創(chuàng)建的Worker的進程數(shù)量
# --pid=/tmp/resque.pid 手動指定PID文件的位置饼丘,適用于單Worker運行方式

php resque start --queue=default --debug=1 --interval=2 --count=5 --pid=/tmp/resque.pid

# 查看進程及殺死進程
ps aux | grep resque |awk ‘{print $2}’|xargs kill

實際應(yīng)用部署過程中注意以守護進程方式啟動

5.1.6. 運行演示

  1. 先啟動Redis服務(wù)

  2. windows下啟動隊列服務(wù) 下圖所示

windows下啟動隊列.png
  1. 客戶端模擬請求入隊(生產(chǎn)者入隊)
客戶端請求入隊.png
  1. 隊列服務(wù)端打印生產(chǎn)者入隊信息及隊列處理信息 下圖所示
入隊信息打印.png
  1. 客戶端輪詢請求獲取隊列處理信息
客戶端輪詢請求.png
  1. 登入redis客戶端查看信息
redis客戶端查看隊列存儲信息.png

項目地址: https://github.com/xiao-xiangyeyu/thinkphp3.2.3-php-resque

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辽话,隨后出現(xiàn)的幾起案子肄鸽,更是在濱河造成了極大的恐慌,老刑警劉巖油啤,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典徘,死亡現(xiàn)場離奇詭異,居然都是意外死亡益咬,警方通過查閱死者的電腦和手機逮诲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幽告,“玉大人梅鹦,你說我怎么就攤上這事∪咚” “怎么了齐唆?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長冻河。 經(jīng)常有香客問我箍邮,道長,這世上最難降的妖魔是什么叨叙? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任锭弊,我火速辦了婚禮,結(jié)果婚禮上摔敛,老公的妹妹穿的比我還像新娘廷蓉。我一直安慰自己,他們只是感情好马昙,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布桃犬。 她就那樣靜靜地躺著,像睡著了一般行楞。 火紅的嫁衣襯著肌膚如雪攒暇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天子房,我揣著相機與錄音形用,去河邊找鬼。 笑死证杭,一個胖子當著我的面吹牛田度,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播解愤,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼镇饺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了送讲?” 一聲冷哼從身側(cè)響起奸笤,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哼鬓,沒想到半個月后监右,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡异希,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年健盒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片称簿。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡味榛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出予跌,到底是詐尸還是另有隱情搏色,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布券册,位于F島的核電站频轿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏烁焙。R本人自食惡果不足惜航邢,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骄蝇。 院中可真熱鬧膳殷,春花似錦、人聲如沸九火。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勒极,卻和暖如春是掰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辱匿。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工键痛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匾七。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓絮短,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昨忆。 傳聞我的和親對象是個殘疾皇子丁频,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容