tp5使用RabbitMQ的使用记录
rabbitmq 官方文档 work queue 的部分
首先希望大家能够关注文档,文档上的内容比较全面,解释的也非常形象。我对此的记录就是写了一下对文档的理解,并且把文档上的内容在TP5中由重新写了一遍。
work queue 工作队列又称为任务队列,我认为这种模式的队列有一下几点是需要关注的。
- 需要明确的是一个队列可以被多个消费者消费
- 在被多个消费者消费的情况下,一个队列里的100个元素会被平均的分配到n个消费者那里。循环调度
- 平均分配到n个消费者那里就会产生一个情况: 100个分到2个消费者那里, 每个消费者各自收获了50个, 第一个消费者把50个任务消费完了。第二个消费者消费到第十个任务的时候,进程挂掉了。所以还剩下40个任务在消费者2这个通道里。就会导致任务的丢失。为了确保消息永远不会丢失,所以,rabbitmq增加了消息确认机制。
- 消息的持久化 消息的持久化要保证channel和queue 的持久化参数都是开启状态。 只开启chanel的持久化肯定是不起作用的。(不能再已有的队列名称的channel中再开一个名字相同的queue。)
- 公平调度 如果有多个消费者, 每个消费者处理任务的速度不一样,为了要做到公平调度,也就是执行任务快的多做一点任务,这行任务慢的少做一些任务。
app\controller\Test.php
channel();
// 创建队列 durable对应true表示开启持久化,当然只设置这一个并没有用
// 需要对消息也设置一个参数 就是50行的 array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
$channel->queue_declare('task_queue', false,true,false,false);
// 循环创建10条消息
for($i=0 ;$i<10;$i++){
$data = "$i Hello World!";
// TODO 初始化消息 待完善
$msg = new AMQPMessage($data, array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT));
// 往消息队列里面发送消息
$channel->basic_publish($msg, '','task_queue');
}
echo ' [x] Sent ', $data, "\n";
// 关闭连接
$channel->close();
$connection->close();
}
}
相关的路由请求文件
这两个文件写完以后,发起一个请求
看到这一句话后,到rabbitmq管理网站上看队列里面有没有数据
接下来我们就要消费这个数据
因为消费数据是需要不断监听rabbitmq服务器传过来的数据,所有我选择有执行命令行来监听服务器。后期就可以执行这个命令脚本了。
app\Command\Recevie.php
setName('receive')
->setDescription('rabbitmq 消费队列');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln("RabbitMQ 消费队列开始启动……\n");
// 创建连接
$connection = new AMQPStreamConnection('localhost', '5672', 'guest', 'guest');
// 创建通道
$channel = $connection->channel();
//创建队列 durable对应true表示开启持久化,当然只设置这一个并没有用
$channel->queue_declare('task_queue', false,true,false,false);
$output->writeln("RabbitMQ 创建通道成功……\n");
$output->writeln("[*] Waiting for messages. To exit press CTRL+C\n");
$callback = function ($msg) use ($output) {
$output->writeln("通过RabbitMQ获取到消费者了,该条消息是: $msg->body \n");
// 消息确认机制 如果不写这一句话的话,在消息队列的unacked那一列就会产生一个未被确认的消息
$msg->ack();
};
// 一个消费者只能获取一个消息队列中的消息,保持消息的完整性和安全性。防止一个消费者获取多个消息,在处理的过程中宕机导致数据丢失
$channel->basic_qos(null, 1, null);
$channel->basic_consume('task_queue', '', false, false, false, false, $callback);
while ($channel->is_open()) {
$channel->wait();
}
}
}
产生这个的原因是下面这一段代码
$channel->basic_qos(null, 1, null);
也就是说在处理并确认前一条消息之前,不要向发送新消息,相反,它会将它分派给下一个不忙的消费者。