php队列使用之php-resque

1. 队列使用场景

1.1. 允许延后|异步|并行处理 (相对于传统的 即时|同步|串行 的执行方式)

  1. 允许延后:抢购活动时,先快速缓冲有限的参与人数到消息队列,后续再排队处理实际的抢购业务;
  2. 允许异步:业务处理过程中的邮件,短信等通知
  3. 允许并行:用户支付成功之后,邮件通知,微信通知,短信通知可以由多个不同的消费者并行执行,通知到达的时间不要求先后顺序。

1.2. 允许失败和重试

  1. 强一致性的业务放入核心流程处理
  2. 无一致性要求或最终一致即可的业务放入队列处理

2. php-resque介绍

php-resque 是轻量级后台任务系统,基于Redis,功能设计简单,配置灵活。相比MQ系统大而全的MQ系统,这个显得小而美

3. php-resque 角色划分

  1. Job 定义任务,是负责具体的业务逻辑。
  2. Queue 队列,负责Job存/取
  3. Worker 从Queue中取Job来执行。 一般为PHP CLI模式下,后台守护方式运行。

4. 场景使用示例

4.1. 场景业务介绍

定点开放约车业务场景中,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列,使任务逐个执行。

4.2. 队列使用流程图

队列使用流程.png

4.3. 环境

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

5. 重要代码示例

5.1.1. 项目目录结构示例1

项目结构示例.png
项目结构示例.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

5.1.3. 生产者发送请求入队核心

php示例代码 : IndexController.class.php

_return(0,"参数有误");
            $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);
            // 入队成功标识,客户端使用此标识定时请求,队列状态查询接口
            $args['jobId'] = $jobId;
            S($key,$args ,5); // 60秒内禁止重复预约
            $this->ajaxReturn(['msg'=>'入队,预约成功','data'=>$args]);
        }catch (\Exception $e){
            $this->ajaxReturn(['异常']);
        }
    }
    //队列状态查询接口
    public function JoinStatus()
    {
        $jobid = I("jobid");
        $status = new \Resque\Job\Status($jobid);
        //执行完成告诉用户是否成功
        if (!$status->isTracking()) {
            $this->_return(0,"不存在的排队");
        }else{
            // 缓存key
            $jobid = "Applet\Controller\V2\BooktrainControllerJoinbook_job".$jobid;
            $info = S($jobid);
            //队列没执行
            if(!$info){
                $info = [];
                $info['msg'] = "等待中...";
                $info['status'] =   100; // 收到该结果 前端继续轮询,一般限制次数轮询
                $this->ajaxReturn($info);
            }
            $this->ajaxReturn($info);  
        }
    }
}

5.1.4. 消费者核心代码

php示例代码 : BooktrainJob.php

args;
        $rid = $args['rid'];
        $subject = $args['subject'];
        $args = array(
            'student_id'=>$args['student_id'] , 
            'rid'=>$rid ,
            'subject'=>$subject
        );
        // 数据库业务逻辑处理-start
        // $deal_info = D('User')->deal($args);
        $deal_info=[];
        $status =$deal_info['status']?:'200';
        $msg =$deal_info['msg']?:'预约成功';
        // 数据库业务逻辑处理-end
        $margs = array(
            'student_id'=>$args['student_id'] , 
            'rid'=>$args['rid'] ,
            'subject'=>$args['subject'],
            'date'=>date('Y-m-d')
        );
        // 终端打印参数
        fwrite(STDOUT,json_encode($args)."\n");

        // 获取当前业务的缓存参数,app请求入队时写入
        $key = "requse".md5(json_encode($margs)); 
        $result = S($key);

        //将业务逻辑处理结果
        $result["status"] = $status;
        $result["msg"] = $msg;

        // 将参数及约车结果放入缓存
        S($key,$result ,1200); 
        
        // 将约车的结果以工作任务标识 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  啰嗦模式启动,会打印详细调试信息
# --interval=2 在队列中循环的间隔时间,即完成一个任务后的等待时间,默认是5秒
# --count=5 需要创建的Worker的进程数量
# --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

实际应用部署过程中注意以守护进程方式启动

5.1.6. 运行演示

  1. 先启动Redis服务

  2. windows下启动队列服务 下图所示

windows下启动队列.png
  1. 客户端模拟请求入队(生产者入队)
客户端请求入队.png
  1. 队列服务端打印生产者入队信息及队列处理信息 下图所示
入队信息打印.png
  1. 客户端轮询请求获取队列处理信息
客户端轮询请求.png
  1. 登入redis客户端查看信息
redis客户端查看队列存储信息.png

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

你可能感兴趣的:(php队列使用之php-resque)