php 消息队列_大厂必备之RabbitMQ:PHP与RabbitMQ消息队列初探

图/文:迷神

近期分享大厂必备之RabbitMQ,RabbitMQ三部曲系列文章第二篇,权作抛砖引玉,希望对大家有用:

(一)大厂必备之RabbitMQ:最新CentOS7系统安装与配置RabbitMQ

(二)大厂必备之RabbitMQ:PHP与RabbitMQ消息队列初探

(三)大厂必备之RabbitMQ:RabbitMQ消息发布与订阅(PHP实现)

RabbitMQ是一个在AMQP基础上实现的企业级消息系统。消息队列是“”消费-生产者模型“”的一个典型的代表,就是一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。

在一些开发项目中,我们可以将一些无需即时返回且耗时的操作提取出来,进行了异步操作,而这种异步处理的方式大大的节省了服务器的请求时间,从而提高了系统的吞吐量。而且不影响服务器做其他相应,不独占服务器资源,实现很好的解耦。

有人会想,为什么不使用redis的队列呢?简单的消息队列,我们完全是可以使用Redis实现,而相对复杂的需求,比如消息确认、消息持久化、高可用等需要用RabbitMQ这样的大器来做比较合适。何况,RabbitMQ也提供了跨语言接口,我们可以使用主流编程语言Java,C,C++,Python,PHP等和RabbitMQ做对接。既强大又方便。

下面我们就来具体使用RabbitMQ,说说,PHP与RabbitMQ消息队列初探

RabbitMQ原理结构图

c2ccd1356aeb434818c1354c87b56101.png

简单结构图

生产者(Producer)和消费者(Consumer)是消息队列的基本概念,生产者是指生产消息的一方,也是消息发送方,消费者就是消费消息的一方,也是消息接收方,队列就是存储消息的一个缓存区。本文实例将由生产者发送很多消息给消息队列,由多个消费者来消费队列中的消息。

这个图形很简单的表示了RabbitMQ的原理。其中,“P”是消息发布者,“C”是消息的消费者,中间红色的是我们的队列,这是一个消息的缓存区。

当然RabbitMQ是很强大的,比上面实际复杂的多,涉及到很多其他方面,具体感兴趣可以自行了解。

安装php-amqplib,连接RabbitMQ

php-amqplib是一个纯PHP库,使用它,基于PHP的脚本客户端就可以轻松的连接和操作RabbitMQ。

composer require php-amqplib/php-amqplib

生产/消息发送

我们模拟了生产者向队列中发送了100条订单消息。

<?php /** * @文件:sender.php * @消息生产者-分发任务 */require_once __DIR__ . '/vendor/autoload.php';use PhpAmqpLibConnectionAMQPStreamConnection;use PhpAmqpLibMessageAMQPMessage;$queue = 'worker';//$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');$connection = new AMQPStreamConnection(    '192.168.0.100',     56720,       'admin',  //user    'admin',  //password    'test'  //vhost);$channel = $connection->channel();$channel->queue_declare($queue, false, true, false, false); //第3个参数设置为true,表示让消息队列持久化for ($i = 0; $i < 100; $i++) {     $arr = [        'id' => 'message_' . $i,        'order_id' => str_replace('.', '' , microtime(true)) . mt_rand(10, 99) . $i,        'content' => 'hello-' . time()    ];    $data = json_encode($arr);  //设置rabbitmq重启后也不会丢失队列,或者设置为'delivery_mode' => 2    $msg = new AMQPMessage($data, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);     $channel->basic_publish($msg, '', $queue);    echo 'Send message: ' . $data . PHP_EOL;}$channel->close();$connection->close();

消息队列(MQ)用来保存消息直到发送给消费者,它是消息的容器。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

消息到达队列中后,如果没有一个消费者来处理消息的话,我们希望队列中的消息不要丢弃,也就是消息持久化。在生产者和消费者中都要将queue_declare第3个参数设置为true,表示让消息队列持久化。

有2个需要注意的:

 //第3个参数设置为true,表示让消息队列持久化$channel->queue_declare($queue, false, true, false, false);//设置rabbitmq重启后也不会丢失队列,或者设置为'delivery_mode' => 2$msg = new AMQPMessage($data, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]); 

消费/消息接收

生产者把消息发布到队列中,剩下就要使用消息者去“消费”接收消息进行处理了。这就像生产线上的操作工人,他们按照操作规程从传送带上取出产品后有序的完成后续工作任务。

当然这里的工人可以一个人,也是多个人,也就是多个消费者来消费队列信息。

默认情况下,RabbitMQ将会把队列中的消息平均分配给每个消费者。如果消费者要对分配到的消息任务处理时间很长(耗时任务),那么处理消息任务的时候就有可能会遇到意外。比如某个消费者断电了,或者出故障了,那它正在处理的消息会怎么办?这里就是RabbitMQ的消息确认机制,为了保证数据不丢失,RabbitMQ会将未处理完的消息分配给下一个消费者处理。

另外,RabbitMQ可以设置公平分配消息任务,不会给某个消费者同时分配多个消息处理任务,因为消费者无法同时处理多个消息任务。换句话说,RabbitMQ在处理和确认消息之前,不会向消费者发送新的消息,而是将消息分发给下一个不忙的消费者。

$channel->basic_qos(null, 1, null); //处理和确认完消息后再消费新的消息

消费者文件receiver.php,代码如下:

<?php /** * @receiver.php * @消息消费者-接收端 */require_once __DIR__ . '/vendor/autoload.php';use PhpAmqpLibConnectionAMQPStreamConnection;$queue = 'worker';$connection = new AMQPStreamConnection('192.168.0.100', 56720, 'admin', 'admin', 'test');$channel = $connection->channel();$channel->queue_declare($queue, false, true, false, false);echo ' [*] Waiting for messages. To exit press CTRL+C' . PHP_EOL;$callback = function($msg){    echo " Received message:", $msg->body, PHP_EOL;    sleep(1);  //模拟耗时执行    $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);};$channel->basic_qos(null, 1, null); //处理和确认完消息后再消费新的消息//第4个参数值为false表示启用消息确认$channel->basic_consume($queue, '', false, false, false, false, $callback); while(count($channel->callbacks)) {    $channel->wait();}$channel->close();$connection->close();

模拟运行

先运行生产者:

php sender.php

再运行消费者,可以运行多个,我们开两个窗口,运行2个消费者测试,client1和client2:

php receive.php

我们可以模拟将其中client1客户端中断,然后再看消息是不是被client2消费者接收处理了。同样我们可以模拟将客户端全部重启,看看队列中的消息是否没有丢失。

当client1中断连接RabbitMQ后,再次运行连接RabbitMQ,在client2中看到的消息处理情况,注意看图中的消息id。

5e915c5f2b557152d8b5039182fa4d5f.png

client1消费端

client2消费端:

272089169ad18cae562f357c87eb7668.png

client2消费端

下一篇分享:大厂必备之RabbitMQ:RabbitMQ消息发布与订阅(PHP实现)

好了,有问题欢迎留言,觉得不错,请记得关注,收藏,点赞哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值