rabbitmq使用场景之(一) 无交换器,直接队列

案例说明

这个案例没有声明交换机和路由键,属于最基础的使用
也就不需要将队列绑定到交换机上并通过路由键去寻找交换机中的队列
就是一个最简单的投递、消费场景

安装 php-amqplib 库

composer require php-amqplib/php-amqplib

自动加载(适用于非框架情况

require_once __DIR__.'/vendor/autoload.php';

引入依赖

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

架构图

image

效果图

image

Index控制器

框架用的thinkphp6
为了简单,生产者和消费者都写在一个控制器里

hello队列名就叫hello

<?php
namespace app\controller;

use app\BaseController;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

class Index extends BaseController
{
    
    const QUEUE = 'hello';
    
    public function index()
    {
        // 要发送的数据
        $data = '这是要被发送的数据';
        $this->send($data);
        return '生产完毕';
    }

    
    
    // 生产者
    public function send(string $data)
    {
        
        
        // 创建hello队列,但不声明交换机
        list($channel,$connection) = self::getChanel(self::QUEUE);

        /**
         *  创建要发送的消息实例,设置消息实例属性
         *      'content_type' => 'text/plain'                            声明传递数据格式为字符串
         *      'delivery_mode'=>AMQPMessage::DELIVERY_MODE_PERSISTENT    使实例其持久化
         */
        $properties = ['content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT];
        $msg = new AMQPMessage($data, $properties);
    
        // 
        /**
         *  作用:
         *      发送消息到hello队列
         *  参数解释:       
         *      $msg         消息内容 
         *      $exchange    交换机(由于此处并未声明交换机,就传递了默认值空串)
         *      $routing_key 路由键(由于此处并未声明路由键,就传递了队列名称hello,使其能找到相应队列)
         *      $mandatory   匹配不到队列时,是否立即丢弃消息
         *      $immediate   队列无消费者时,是否立即丢弃消息
         *      $ticket      
         */
        $channel->basic_publish($msg , '', self::QUEUE, false , false , null );
    
        // 关闭通道
        $channel->close();
    
        // 关闭连接
        $connection->close();
    }

    
    // 消费者
    public static function receive()
    {
         list($channel,$connection) = self::getChanel(self::QUEUE);

        /*  
            作用:
                接收生产者传递而来的消息,并开始消费hello队列的消息
            参数解释:
                queue: 消息来源的队列
                consumer_tag: 消费者标识符
                no_local: 不接收此消费者发布的消息
                no_ack: 如果设置为true,将使用自动确认模式。详情请参阅 https://www.rabbitmq.com/confirms.html,不可与手动应答ack同存,否则会报:unknown delivery tag 1重复消费信息错误
                exclusive: 请求独占消费者访问权,意味着只有该消费者可以访问队列
                nowait:
                callback: PHP回调函数(业务代码逻辑编写在此处)
        */
        $channel->basic_consume(self::QUEUE, '', false, false, false, false, [self::class, 'callback']);
        /*
            作用:
                控制消费者处理消息的速度,避免在繁忙时期一次性获取过多的消息而导致过载或者资源浪费。通过限制每次最多接收的消息数,可以平衡消费者和 RabbitMQ 之间的负载,提高系统的稳定性和可靠性。
            参数解释:
                prefetch_size   第一个参数 null 表示不限制 
                1               第二个参数 表示每次最多接收 1 条未确认消息
                global          第三个参数 null 表示不限制 。
        */
        $channel->basic_qos(null,1,null); 
        while ($channel->is_open()) {
            $channel->wait();
        }
    }

    // 消费者真正执行的业务代码
    public static function callback($msg)
    {
       
        echo "接收到消息:", $msg->body, "\n";
        // trace($msg->body, 'info');

        // 向RabbitMQ做出应答,表示本条消息已处理完毕,可以开始下一条消息的处理
        $msg->ack();
    }

    /**
     * 创建信道,声明使用信道中的哪个队列
     * $queue 队列名称
     **/
    public static function getChanel($queue)
    {
        $config = [
            'host'      =>'localhost',      // RabbitMQ服务器主机IP地址
            'port'      => 5672,            // RabbitMQ服务器端口
            'user'      => 'your username',         // 连接RabbitMQ服务器的用户名
            'password'  => 'your password',        // 连接RabbitMQ服务器的用户密码
            'vhost'     => '/'              // 连接RabbitMQ服务器的vhost(可以有多个vhost)
        ];
        extract($config);

        // 创建连接
        $connection = new AMQPStreamConnection($host, $port, $user, $password, $vhost);

        // 连接后创建信道
        $channel = $connection->channel();

        /*
            作用:
                声明队列
            参数解释:
                name: $queue       // 队列名称
                passive: false          // 是否检测同名队列
                durable: true           // 队列将在服务器重启后仍然存在
                exclusive: false        // 其他通道可以访问队列
                auto_delete: false      // 通道关闭后队列不会被删除
        */
        $channel->queue_declare($queue, false, false, false, false);

        return [$channel, $connection];
    }
}


Hello指令

<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

//  引入控制器
use app\controller\Index;

class Hello extends Command
{

    
    protected function configure()
    {
        // 指令配置
        $this->setName('hello')
             ->setDescription('RabbitMQ的hello队列');
    }

    protected function execute(Input $input, Output $output)
    {
        // 执行消费
        Index::receive();
        
        // 指令输出
        // $output->writeln('i see');
    }
}

posted @ 2024-05-16 17:51  Anbin啊  阅读(29)  评论(0)    收藏  举报