为什么80%的码农都做不了架构师?>>>
虽然接触过几门语言,但是在大佬们谈论队列的时候还总是像是一座大山,经过一段时间的整理,以下我来谈谈我对队列的看法(路过大神扶正请温柔)。
== 关于队列 ==
1.队列就像是一个容器,把来不及操作的东西井然有序的放入。
2.通俗的讲,可以把队列看做一个城市的马路。有很多马路,各有各的秩序和走向,先驶入的先走出马路,马路与马路车辆不会相互影响。队列里的内容是有一定规格的,就想机动车和非机动车一样,相同规格的在相同的路上行进。
3.队列就像线性表一样,两头都可以操作,但是表头只出表尾只进,表中的内容只是进行存储。
这样看难点就在于,表存在什么地方,在表中的数据什么时候取出,操作失败之后要怎么办等。于是这个时候就需要驱动,扩展,插件等来辅助了。
== 关于 yii2-queue YII原生福利 ==
1,安装
利用composer快速安装 . php composer.phar require --prefer-dist yiisoft/yii2-queue
2,配置
在config中添加配置‘queue’的信息。由于这个yii原生的队列可以支持多种驱动,所以在配置前还是要先选好驱动。
参考:https://github.com/yiisoft/yii2-queue/tree/master/docs/guide-zh-CN
测试实例:示例是console的config/main.php中配置方式
1.File
这里的第一个queue是file驱动型。是把放入队列的数据加密存储成一个个文件(可能会被规则命名为job1.data的形式)。这里要注意path。由于YII的每个项目中存在多个APP,配置文件可以相互独立,队列在项目前端APP中进行添加,所以需要在该APP配置队相同的内容,但是要注意一点,这里的path需要指到相同的位置。
2.Redis
第三个是redis驱动,这里要注意的是redis是要另外配置,可以在common的APP中config/main-local.php。配置方式类似下图:
另外DB形式和redis类似,配置好db部分和queue部分(redis也可以看做是非关系型数据库的一种,这里对数据存储处理几乎一致)
3.Beanstalk
作为主流驱动兔子比较受欢迎,但是兔子系列的基本都是比较大型的,一般小项目PHP选用beanstalk也比较多。(而且就个人原因手上的旧项目选用的也是这个,在使用和表述上有据可考也是极好)所以我原则beanstalk进行深入表述
beanstalk是可以在其他框架下仍然好用的软件,这里我要从三种不同的方式操作。首先就是今天的主题,利用YII2-queue,其二是用udokmeci\yii2beanstalk,第三就是pheanstalk。这三种都是对beanstalk进行操作,三者可以交错使用。
------ 利用yii2soft/yii2-queue ------
其中的存储类型是特殊的,我们需要先新建一个类。
url = $array['url'];
$this->file = $array['file'];
return $this;
}
//这个函数是必须要有的因为接口的实现,这里的函数是在队列入队执行的
public function execute($queue)
{
echo '我正在执行队列。。。';
var_dump($this);
file_put_contents($this->file, file_get_contents($this->url));
}
//这个是对队列任务的延迟设置
public function getTtr()
{
echo 'ttr';
return 15 * 60;
}
//设置任务的延迟重复
public function canRetry($attempt, $error)
{
echo 'can try';
return ($attempt < 5) && ($error );
}
}
我的这个类叫BaseJob,所以之后的队列如果利用yii2-queue进行封装入队时就需要用这里类作为存储。
例如在需要入队的时候:
$id_11 = Yii::$app->queue->push(new BaseJob([
'url' => 'http://img3.imgtn.bdimg.com/it/u=1243131531,3821032402&fm=27&gp=0.jpg',
'file' => '../runtime/tmp/image.jpg',
]));
当然数据结构是根据个人而定,这里是可以完成图片下载的逻辑,入队的是图片下载地址和将下载存储的地址。队列中数据的处理则写在execute()中
那么问题出来了,数据在什么时候才能出队?什么时候才能执行?和其他驱动类似,我们可以用:php yii queue/listen
来监听队列,如果非延迟任务入队将直接执行相应的exectue。延迟任务则在相应时间之后执行。另外还可以使用:php yii queue/info 来检查队列状态。php yii remove [id] 来移除指定的ID任务。等等命令,这些都是通过在console配置直接执行的。队列情况实例如下:
== 关于 beanstalk ==
在正式开始之前就涉及到一个关于提供服务问题,在上一个模块的最后提到了关于beanstalk.这里出现一个问题,我的实例代码是按照本机是提供服务配置的,显然这里提供服务的是本机,如果需要其他的机子就换掉IP和端口就好,但是要吧本机作为主机嘞~
1.配置beanstalk服务主机。
(1)安装(基于MAC)
brew install beanstalk
(2)确认安装成功
执行相关帮助或查询版本的命令;例如:beanstalk -h
(3)开启服务
beanstalk -l 地址 -p 端口号
参考资料:
http://blog.csdn.net/ahjxhy2010/article/details/53196450
https://segmentfault.com/a/1190000002784775
http://www.51siyuan.cn/91.html
https://getyii.com/topic/531
2.基于beanstalk的入队操作
参考:
http://blog.csdn.net/taotaobaobei/article/details/78570963
http://blog.csdn.net/taotaobaobei/article/details/78571063
很多网站上都没又说这两个的区别,方法也是混着用的,(或许在其他框架是一样的)但是YII在两种的入队方式不大相同。
(1)udokmeci\yii2beanstalk
(a)安装 :composer require udokmeci\yii2beanstalk
(b)使用:
(i)配置
'beanstalk'=>[
'class' => 'udokmeci\yii2beanstalk\Beanstalk',
'host'=> "127.0.0.1", // default host
'port'=>11300, //default port
'connectTimeout'=> 1,
'sleep' => false, // or int for usleep after every job
],
(ii)入队
$bean = Yii::$app->beanstalk;
$bean->putInTube('tubequeue',['unique_id' => 11, 'source' => 2, 'method'=> 'get']);
这里入队的时候有较大区别,但在执行的时候都是一个文件
(2)pda/pheanstalk(https://github.com/pda/pheanstalk/)
(a)安装 :composer require pda/pheanstalk
(b)执行
(i)配置:
看起来主流的都是实例化对象进行调用,并没配置,不过可以封装一个类自动填写实例化内容
(ii)入队。这里要注意的是,入队的内容要转成JSON格式
这个是主流PHP中对beanstalk的操作依赖,可以有较灵活的操作,获取状态,管道名称个数,获取某个管道的状态信息等
(3)yii-queue
安装和入队和前面讲的一样。
3.关于beanstalk的执行
利用上面提到的(1),(2)两种。数据处理的类别是要集成BeanstalkController的。例如:
getData();
//相应操作
}
catch (\Exception $e) {
//If there is anything to do.
fwrite(STDERR, Console::ansiFormat($e."\n", [Console::FG_RED]));
// you can also bury jobs to examine later
return self::BURY;
}
}
public function actionTubequeue($job){
try {
$sentData = $job->getData();
//相应操作
}
catch (\Exception $e) {
//If there is anything to do.
fwrite(STDERR, Console::ansiFormat($e."\n", [Console::FG_RED]));
// you can also bury jobs to examine later
return self::BURY;
}
}
/**
*
* @param Pheanstalk\Job $job
* @return string self::BURY
* self::RELEASE
* self::DELAY
* self::DELETE
* self::NO_ACTION
* self::DECAY
*
*/
public function actionTube($job){
// $sentData = $job->getData();
try {
$sentData = $job->getData();
//相应操作
// something useful here
// if you return anything else job is burried.
} catch (\Exception $e) {
//If there is anything to do.
fwrite(STDERR, Console::ansiFormat($e."\n", [Console::FG_RED]));
// you can also bury jobs to examine later
return self::BURY;
}
}
}
上面是一个简单的示例,没有对取到的数据做任何操作,只是去取出各种存入的数据。只看其中必要问题。
要点一:
对于: listenTubes()是表述监听的tube的名字。类似于php yii queue/listen的作用,会主动开启监听。
要监听多个tbue时。就要写成数组的形式。
要点二:
对于不同tbue的操作是利用不同函数区分,函数要用tube的名字命名。要注意对不同处理结果的处理
另外再补充几个借鉴资料的文章:
http://www.360doc.com/content/16/0712/11/9200790_574926294.shtml
https://www.cnblogs.com/yingmo/p/6148380.html
http://www.yiichina.com/extension/1084
http://www.mamicode.com/info-detail-1485697.html