tp6中使用rabbitmq

1 先composer安装类库

composer requirer  php-amqplib/php-amqplib

2 新建配置文件 config/rabbitmq.php


    return [

        # 连接信息
        'AMQP' => [
            'host' => '127.0.0.1',
            'port'=>'5672',
            'login'=>'guest',
            'password'=>'guest',
            'vhost'=>'/'
        ],
        # 邮件队列
        'email_queue' => [
            'exchange_name' => 'email_exchange',
            'exchange_type'=>'direct',#直连模式
            'queue_name' => 'email_queue',
            'route_key' => 'email_roteking',
            'consumer_tag' => 'consumer'
        ]
];

3 新建两个类,一个生产者,一个消费者,生产者把消息推送到队列,推送完可以断开连接,消费者要保持一直开启状态消费者保持开启状态的方式1 linux上写定时任务每隔5分钟运行下该脚本,保证访问服务器的ip比较平缓,不至于崩溃2 nohup php index.php index/Message_Consume/start & 用nohup命令后台运行该脚本3 使用Supervisor.以上都是在linux 上的后台执行的方法,在windows上我们只能用命令行做了,当然windowns可以用任务计划做,有兴趣的同学自己去研究下.我们现在把生产者写成接口的形式,消费者一般都写成命令行的方式或者脚本的形式,因为消费者要保持开启的状态

生产者


namespace app;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use think\facade\Log;

class MqProducer
{
    public static function pushMessage($data)
    {
        $param = config('rabbitmq.AMQP');
        $amqpDetail = config('rabbitmq.email_queue');
        $connection = new AMQPStreamConnection(
            $param['host'],
            $param['port'],
            $param['login'],
            $param['password'],
            $param['vhost']
        );
        $channel = $connection->channel();
        /*
             name: $queue  创建队列
             passive: false
             持久durable: true // //队列将在服务器重启后继续存在
             互斥exclusive: false // 队列可以通过其他渠道访问
             auto_delete: false 通道关闭后,队列不会被删除
         */
         $channel->queue_declare($amqpDetail['queue_name'], false, true, false, false);

         /*
             name: $exchange  创建交换机
             type: direct   直连方式
             passive: false
             durable: true  持久// 交换器将在服务器重启后继续存在
             auto_delete: false //一旦通道关闭,交换器将不会被删除。
         */
        $channel->exchange_declare($amqpDetail['exchange_name'], 'direct', false, true, false);

        /*
             $messageBody:消息体
             content_type:消息的类型 可以不指定
             delivery_mode:消息持久化最关键的参数
             AMQPMessage::DELIVERY_MODE_NON_PERSISTENT = 1;
             AMQPMessage::DELIVERY_MODE_PERSISTENT = 2;
         */
        $messageBody = $data;
        $message = new AMQPMessage($messageBody, array('content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT));
        $channel->basic_publish($message, $amqpDetail['exchange_name'],$amqpDetail['route_key']);
        $channel->close();
        $connection->close();
        echo  "ok";
    }
}

消费者代码


namespace app;

use PhpAmqpLib\Connection\AMQPStreamConnection;
use think\facade\Log;

class MqConsumer
{
    /**
     * 消费端 消费端需要保持运行状态实现方式
     * 1 linux上写定时任务每隔5分钟运行下该脚本,保证访问服务器的ip比较平缓,不至于崩溃
     * 2 nohup php index.php index/Message_Consume/start &  用nohup命令后台运行该脚本
     * 3
     **/
    function shutdown($channel, $connection)
    {
        $channel->close();
        $connection->close();
        Log::write("closed",3);
    }

    function process_message($message)
    {
        echo  $message->body."\n";
        //手动发送ack
        $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);
        // Send a message with the string "quit" to cancel the consumer.
        if ($message->body === 'quit') {
            $message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
        }
    }

    /**
     * 启动
     * @return \think\Response
     */
    public function start()
    {
        $param = config('rabbitmq.AMQP');
        $amqpDetail = config('rabbitmq.email_queue');
        $connection = new AMQPStreamConnection(
            $param['host'],
            $param['port'],
            $param['login'],
            $param['password'],
            $param['vhost']
        );
        $channel = $connection->channel();
        $channel->queue_declare($amqpDetail['queue_name'], false, true, false, false);
        $channel->exchange_declare($amqpDetail['exchange_name'], 'direct', false, true, false);
        $channel->queue_bind($amqpDetail['queue_name'], 				   $amqpDetail['exchange_name'],$amqpDetail['route_key']);

        /*
            queue: 从哪里获取消息的队列
            consumer_tag: 消费者标识符
            no_local: 不接收此使用者发布的消息
            no_ack: 如果求设置为true,则此使用者将使用自动确认模式。详情请参见.
            exclusive:请独占使用者访问,这意味着只有这个使用者可以访问队列
            nowait:
            callback: :PHP回调 array($this, 'process_message') 调用本对象的process_message方法
        */

        $channel->basic_consume($amqpDetail['queue_name'], $amqpDetail['consumer_tag'], false, false, false, false, array($this, 'process_message'));
        register_shutdown_function(array($this, 'shutdown'), $channel, $connection);
        while (count($channel->callbacks)) {
            $channel->wait();
        }
    }
}

4 以上是生产者和消费者的两个类,下面我们把我们先自定义一个命令行,然后用这个命令行执行我们的消费者去消费消息
php think make:command Consumer生成命令行,稍作修改



declare (strict_types = 1);

namespace app\command;

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

class Consumer extends Command
{
    protected function configure()
    {
        // 指令配置
        $this->setName('consumer')//自定义的命令 php think consumer 这样去调用了
            ->setDescription('the consumer command');
    }

    protected function execute(Input $input, Output $output)
    {
        $consumer = new MqConsumer();
        $consumer->start();//调用消费者
    }

当然tp框架自定义命令行还需要把该命令添加到config/console.php中

添加命令到配置文件config/console.php


return [
    // 指令定义
    'commands' => [
    	// consumer是app\Command\Consumer文件中自定义命令行的名字
        'consumer' => 'app\Command\Consumer'
    ],
];

添加完后测试php think consumer 命令是否有效

5 消费者写好后,我们控制器写一个接口,模拟用户访问


namespace app\controller;
use app\BaseController;
use app\MqProducer;

class Index extends BaseController
{
    public function send()
    {
        $consumer = new MqProducer();//生产者
        $consumer->pushMessage('time:'.time().' your mother call you back home ');
    }
}

6 当然我们也可以用ab压力测试模拟下并发访问,但是先开启消费端 才能看到效果

ab  -n 100 -c 10 127.0.0.1/think/public/index.php/send  
-n 访问次数
-c 并发量

tp6中使用rabbitmq_第1张图片

你可能感兴趣的:(TP使用rabbitmq)