工作队列(又称:任务队列——Task Queues)是为了避免等待一些占用大量资源、时间的操作。当我们把任务(Task)当作消息发送到队列中,一个运行在后台的工作者(worker)进程就会取出任务然后处理。当你运行多个工作者(workers),任务就会在它们之间共享。

这个概念在网络应用中是非常有用的,它可以在短暂的HTTP请求中处理一些复杂的任务。

一、准备

  1、使用 sleep()函数来模拟复杂任务情况。我们在字符串中加上点号(.)来表示任务的复杂程度,一个点(.)将会耗时1秒钟。比 如”Hello…”就会耗时3秒钟

  2、生成者

  

<?php

/**
* PHP amqp(RabbitMQ) Demo-2
*/ $exchangeName = 'demo';
$queueName = 'task_queue';
$routeKey = 'task_queue';
$message = empty($argv[1]) ? 'Hello World!' : ' '.$argv[1]; $connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest'));
$connection->connect() or die("Cannot connect to the broker!\n"); $channel = new AMQPChannel($connection); $exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName); $queue = new AMQPQueue($channel);
$queue->setName($queueName);
$queue->setFlags(AMQP_DURABLE);//声明为持久化
$queue->declareQueue(); $exchange->publish($message, $routeKey);
var_dump("[x] Sent $message"); $connection->disconnect();

  3、消费者

  

<?php

/**
* PHP amqp(RabbitMQ) Demo-2
*/
$exchangeName = 'demo';
$queueName = 'task_queue';
$routeKey = 'task_queue';//路由关键字
//连接
$connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest'));
$connection->connect() or die("Cannot connect to the broker!\n");
//消息通道
$channel = new AMQPChannel($connection);
//消息交换机
$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setType(AMQP_EX_TYPE_DIRECT);
$exchange->declareExchange();
//消息队列
$queue = new AMQPQueue($channel);
$queue->setName($queueName);
$queue->setFlags(AMQP_DURABLE);//声明为持久化
$queue->declareQueue();
$queue->bind($exchangeName, $routeKey);//绑定 var_dump('[*] Waiting for messages. To exit press CTRL+C');
while (TRUE) {
$queue->consume('callback');
//告诉RabbitMQ,再同一时刻,不要发送超过1条消息给一个工作者(worker),直到它已经处理了上一条消息并且作出了响应
$channel->qos(0,1);
}
$connection->disconnect(); function callback($envelope, $queue) {
$msg = $envelope->getBody();
var_dump(" [x] Received:" . $msg);
sleep(substr_count($msg,'.'));//计算.在$msg中出现的次数
//消费者会通过一个ack(响应),告诉RabbitMQ已经收到并处理了某条消息,然后RabbitMQ就会释放并删除这条消息
$queue->ack($envelope->getDeliveryTag());
}

二、轮询分发

  1、默认来说,RabbitMQ会按顺序得把消息发送给每个消费者(consumer)。平均每个消费者都会收到同等数量得消息。这种发送消息得方式叫做——轮询(round-robin)。试着添加两个个或更多得工作者(workers)。

  2、首先,我们先同时运行两个worker.php脚本,它们都会从队列中获取消息,我们需要打开三个终端,两个用来运行worker.php脚本,这两个终端就是我们的两个消费者(consumers)—— C1 和 C2。然后剩下一个终端运行生产者new_task.php脚本,你会发现如果我们发送消息得任务复杂度一样的话,C1和C2会轮询处理消息。

三、消息响应

  当处理一个比较耗时得任务的时候,消费者(consumers)有时会运行到一半就挂掉。当消息被RabbitMQ发送给 消费者(consumers)之后,马上就会在内存中移除。这种情况,你只要把一个工作者(worker)停止,正在处理的消息就会丢失。同时,所有发送 到这个工作者的还没有处理的消息都会丢失。

我们不想丢失任何任务消息。如果一个工作者(worker)挂掉了,我们希望任务会重新发送给其他的工作者(worker)。

为了防止消息丢失,RabbitMQ提供了消息响应(acknowledgments)。消费者会通过一个ack(响应),告诉RabbitMQ已经收到并处理了某条消息,然后RabbitMQ就会释放并删除这条消息。

如果消费者(consumer)挂掉了,没有发送响应,RabbitMQ就会认为消息没有被完全处理,然后重新发送给其他消费者(consumer)。这样,即使工作者(workers)偶尔的挂掉,也不会丢失消息。

function callback($envelope, $queue) {
$msg = $envelope->getBody();
var_dump(" [x] Received:" . $msg);
sleep(substr_count($msg,'.'));
$queue->ack($envelope->getDeliveryTag());//消费者发送ack响应
}
$queue->consume('callback');

运行上面的代码,我们发现即使使用CTRL+C杀掉了一个工作者(worker)进程,消息也不会丢失。当工作者(worker)挂掉后,所有没有响应的消息都会重新发送。

  

四、消息持久化

  如果你没有特意告诉RabbitMQ,那么在它退出或者崩溃的时候,它将会流失所有的队列和消息。为了确保信息不会丢失,有两个事情是需要注意的:我们必须把“队列”和“消息”设为持久化。

首先,为了不让队列丢失,需要把它声明为持久化(durable):

$queue->setFlags(AMQP_DURABLE);

尽管这行代码本身是正确的,但是仍然不会正确运行。因为我们已经定义过一个叫hello的非持久化队列。RabbitMq不允许你使用不同的参数重新定义一个队列,它会返回一个错误。但我们现在使用一个快捷的解决方法——用不同的名字,例如task_queue。

$queue->setName('task_queue');
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue();

这个$queue->declareQueue();必须在生产者(producer)和消费者(consumer)对应的代码中修改。

这时候,我们就可以确保在RabbitMq重启之后queue_declare队列不会丢失。

五、公平分发

你应该已经发现,它仍旧没有按照我们期望的那样进行分发。比如有两个工作者(workers),处理奇数消息的比较繁忙,处理偶数消息的比较轻松。然而RabbitMQ并不知道这些,它仍然一如既往的派发消息。

这时因为RabbitMQ只管分发进入队列的消息,不会关心有多少消费者(consumer)没有作出响应。它盲目的把第n-th条消息发给第n-th个消费者。

我们可以使用$channel->qos();方法,并设置prefetch_count=1。这样是告诉RabbitMQ,再同一时刻,不要发送超过1条消息给一个工作者(worker),直到它已经处理了上一条消息并且作出了响应。这样,RabbitMQ就会把消息分发给下一个空闲的工作者(worker)。

$channel->qos(0,1);

原文:https://www.cnblogs.com/grimm/p/5728743.html

												

RabbitMq学习3-工作队列(Work queues)的更多相关文章

  1. (转) RabbitMQ学习之工作队列(java)

    http://blog.csdn.net/zhu_tianwei/article/details/40887717 参考:http://blog.csdn.NET/lmj623565791/artic ...

  2. RabbitMQ学习总结 第三篇:工作队列Work Queue

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  3. RabbitMQ入门教程(四):工作队列(Work Queues)

    原文:RabbitMQ入门教程(四):工作队列(Work Queues) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https:/ ...

  4. RabbitMQ学习第二记:工作队列的两种分发方式,轮询分发(Round-robin)和 公平分发(Fair dispatch)

    1.什么是RabbitMQ工作队列 我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据.因此如果一 ...

  5. RabbitMQ学习总结 第一篇:理论篇

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  6. RabbitMQ学习总结 第二篇:快速入门HelloWorld

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  7. RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  8. RabbitMQ学习总结 第五篇:路由Routing

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  9. RabbitMQ学习总结 第六篇:Topic类型的exchange

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  10. RabbitMQ 学习专栏

    RabbitMQ 官网:http://www.rabbitmq.com/ 原创博文 1.揭开消息中间件RabbitMQ的神秘面纱 2. RabbitMQ 服务器之下载安装 3. RabbitMQ 之修 ...

随机推荐

  1. TF-epoch、 iteration和batchsize区别(转载)

    from http://www.cnblogs.com/qggg/p/6876942.html 转自 http://blog.csdn.net/sinat_30071459/article/detai ...

  2. Python pickle模块学习(超级详细)

    from  http://blog.csdn.net/sxingming/article/details/52164249

  3. 在 Cloudera Data Flow 上运行你的第一个 Flink 例子

    文档编写目的 Cloudera Data Flow(CDF) 作为 Cloudera 一个独立的产品单元,围绕着实时数据采集,实时数据处理和实时数据分析有多个不同的功能模块,如下图所示: 图中 4 个 ...

  4. Cassandra 数据一致性

    基本概念 一致性: 在分布式系统中的所有数据备份,在同一时刻是否同样的值 QUORUM: 是一个可以计算的数字,对数据一致性起重要作用 Node: 主要用来存储数据 Data Center: 数据中心 ...

  5. 【CF1250G】Discarding Game(DP)

    题意:A和B玩游戏,一共n轮,A先B后,第i轮两人分别能得到a[i]和b[i]的得分,累加到当前得分和中 每一轮进行完之后A可以选择抵消得分,即两者都减去两者的min 若某个时刻某个人得分和不小于K则 ...

  6. 一个超详细vue无限滚动vue-infinite-scroll插件的配置及使用详解

    开发中总会遇到这种下拉加载的设计方案,Vue实现下拉加载最佳方案自然是使用vue-infinite-scroll来实现.接下来我们一起看下它的配置及使用方式. 首先我们先了解下他的配置参数: v-in ...

  7. C# 前台和后台POST提交信息的实现方法

    一.系统A(官网)与系统B(第三方支付平台)数据交换的方式 1.1  页面浏览器方式:系统A以构造Form表单的方式,通过系统A客户的浏览器重定向到系统B(向系统B发送请求),B系统完成交易后,将交易 ...

  8. (转)IIS Express介绍与使用

    IIS Express是什么?IIS Express是为开发人员优化的轻量级.自包含版本的IIS.IIS Express使使用当前最新版本的IIS来开发和测试网站变得容易.它具有IIS 7及以上的所有 ...

  9. Java第一次学习总结

    学习内容: 1.java是本学期刚刚接触新的一种编程语言,与大一C语言在语法上有很多相同之处,不同的是在很多问题上,更加简练,更加易于理解. 例如:输出水仙花数,从C语言近五十行代码缩短近十几行,数据 ...

  10. POJ 1625 Censored ( Trie图 && DP && 高精度 )

    题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中 ...