• 实现异步执行任务的队列


    一、队列使用场景:为什么需要队列
    在web开发中,我们经常会遇到需要处理批量任务的时候,这些批量任务可能是用户提交的,也可能是当系统被某个事件触发时需要进行批量处理的,面对这样的 任务,如果是用户提交的批量任务,初级程序员只能让用户触发提交动作后,等待服务器处理完毕,并且将结果返回到浏览器,期间用户不能关掉浏览器窗口,如果 数据比较大,或者处理速度比较慢,那用户体验将会因此受到直接影响。但是当我们使用某讯或者某浪的邮箱时,点击群发邮件之后,只需等待很短的时间,浏览器 提示提交成功,正在发送之类的信息时,用户就可以关掉浏览器,稍后,收件地址栏里的邮箱将陆续收到该群发邮件,再比如群发定时邮件,以及当商城系统中有客 户下单,客户,客服,仓库等相关人员收到订单邮件信息。诸如此类,队列的应用范围是如此之广。

    二 :普通工程师的解决方案和架构师的解决方案
    方案1:建表存邮件,消息等,用定时程序取出发送。

    方案2:抽象到更高一层,开发一套通用异步处理队列适用于任何复杂的业务逻辑
    那么,作为架构师,使用队列的做法,将抽象层和业务层分离,可具有良好的扩展性和可维护性。相比较而言就高明了许多,下面就我们介绍一下自定义队列的实现思路和方法。

    三 :队列总体设计

    1:需要队列程序,提供加入队列接口和取队列接口等
    2:需要存储队列,文件或者数据库
    3:需要定时程序取出队列并执行
    4:其它扩展功能:优先级,日志,定时等

    代码的目录结构如下,每个文件的作用用//注释来标明
    |--addTask.php //添加任务到队列的例子
    |--cronMission.php //定时任务调度程序,例如linux中受crontab直接调用的文件,业务逻辑工程师可以在这个文件中灵活定义自己的队列任务,从而不用每个队列任务 都需要上服务器修改crontab,从而在安全性,便捷性方面有很大提高
    |--db.php //数据库操作
    |--db.sql //建立队列需要用到的基本表结构
    |--doQueue.php //执行队列任务
    |--Queue.class.php //队列核心业务在这里定义,包括将任务加入队列,读队列,更改队列任务状态
    |--sendMsg.php //队列要实现具体任务的业务接口,比如现有系统的发送消息的接口,这里例子中因为将此队列程序和现有系统系统集成,用写入日志来演示

    四 :队列具体实现一:建任务存储表
    1:
    先来个最基本的:

    CREATE TABLE`queue` (
     id int(11) NOT NULL auto_increment primarykey,
     taskphp varchar(128) NOT NULL default '',
     param text not null default '',
     status tinyint not null default 0,
     ctime timestamp NOT NULL default CURRENT_TIMESTAMP,
     KEY (ctime)
    ) ENGINE=InnoDBDEFAULT CHARSET=utf8;
    

    字段解释:
    taskphp:处理业务的接口文件
    param:处理业务的接口文件需要接收的参数
    status:任务处理状态,0为未处理,处理完毕更改为1

    五 、队列具体实现二:定义调用接口

    写核心类Queue.class.php, 实现基本接口:
    1:加入队列接口
    l //$param1 为执行任务的程序,$param2 为程序参数,可以为序列化的数据
    l $cqueue->add($param1,$param2);
    2: 读取队列接口
    l $tasks = $cqueue->getQueueTask($limit = 1000);
    3:更新任务状态
    l $cqueue->updateTaskStatus($id);
    4:a2s是自定义的一个数组转换字符串方法,这里不要使用json_encode,容易出现问题,同样,从数据库中取出转换为数组的时候,使用s2a方法
    l $re = $cqueue->add("sendMsg.php", Queue::a2s($arr));

      1 <?php
      2 /**
      3  * 优才网公开课示例代码
      4  *
      5  * 任务队列实现
      6  *
      7  * @author 优才网全栈工程师教研组  张友林
      8  * @see http://www.ucai.cn
      9  */
     10 
     11 include_once('db.php');
     12 class Queue
     13 {
     14 
     15     /**
     16      * 把任务扔到队列
     17      *
     18      * @param string $taskphp   执行任务的程序
     19      * @param string $param     执行任务程序所用的参数
     20 
     21      * 例如,群发消息加入队列:
     22      * $arr = array(
     23      *      "uid" => 4,//发信息的人的UID
     24      *      "uids" => array(6,234,34,67,7888,2355), //接收信息的人的UID
     25      *      "content" => 'xxxxx',//信息内容
     26      *  );
     27      * $cqueue = new Queue();
     28      * $cqueue->add("/app/send_msg.php", serialize($arr));
     29      *
     30      */
     31     public function add($taskphp,$param)
     32     {
     33         $taskphp = mysql_real_escape_string($taskphp);
     34         //$param = mysql_real_escape_string($param);
     35         $param = $param;
     36         $sql = "insert into queue (taskphp, param) values('".$taskphp."', '".$param."')";
     37         $re = execute($sql);
     38         if ($re)
     39         {
     40             $pid = mysql_insert_id();
     41             return $pid;
     42         }
     43         else
     44         {
     45             return false;
     46         }
     47     }
     48 
     49 
     50     /**
     51      * 读取任务队列
     52      * 
     53      * @param string $limit 一次取多少条
     54      */
     55      public function getQueueTask($limit = 1000)
     56      {
     57         $limit = (int)$limit;
     58         $sql = "select id, taskphp, param from queue  where status = 0 order by id asc";
     59         $re = query($sql);
     60         return $re;
     61      }
     62 
     63     /**
     64      * 更新任务状态
     65      * 
     66      * @param string $limit 一次取多少条
     67      */
     68      public function updateTaskByID($id)
     69      {
     70         $id = (int)$id;
     71         $mtime = time();
     72         $sql = "update queue  set status =1, mtime = ".$mtime." where id = ".$id;
     73         $re = execute($sql);
     74         return $re;
     75      }
     76 
     77 
     78      public static function a2s($arr)
     79     {
     80         $str = "";
     81         foreach ($arr as $key => $value)
     82         {
     83             if (is_array($value))
     84             {
     85                 foreach ($value as $value2)
     86                 {
     87                     $str .= urlencode($key) . "[]=" . urlencode($value2) . "&";
     88                 }
     89             }
     90             else
     91             {
     92                 $str .= urlencode($key) . "=" . urlencode($value) . "&";
     93             }
     94         }
     95         return $str;
     96     }
     97 
     98     public static function s2a($str)
     99     {
    100         $arr = array();
    101         parse_str($str, $arr);
    102         return $arr;
    103     }
    104 
    105 }
    106 
    107 ?>

    接下来就是部署调度了, 这个呢也不是就配置crontab那么简单,要可维护性,可扩展性好,能多进程并发执行,能监控队列运行状态等等,太长了,这个下一篇讲。

  • 相关阅读:
    禁止Crontab产生邮件
    centos6.2 ftp 配置
    [转] 夏天折T恤的方法
    [转] 55个经典开源Windows工具(2)
    [转] 55个经典开源Windows工具(3)
    [**轻松一下**] 程序员喝酒喝出的计算机文化!
    [转] 55个经典开源Windows工具(1)
    [转] 关于mscomm的用法,提高篇
    [转] 传说中的减肥............
    [转] 关于MSCOMM控件的一些说明
  • 原文地址:https://www.cnblogs.com/mmady/p/6605633.html
Copyright © 2020-2023  润新知