RabbitMQ+PHP


介绍:RabbitMQ 是一个消息代理:它接受和转发消息。您可以将其视为邮局:当您将要邮寄的邮件放入邮箱时,您可以确定邮递员最终会将邮件递送给您的收件人。在这个类比中,RabbitMQ 是一个邮箱、一个邮局和一个邮递员。

官网地址:https://www.rabbitmq.com/

一、 安装 RabbitMQ 服务端

- ​ Docker 安装

# 拉取镜像:选择带有 management(包含web管理界面)
docker pull rabbitmq:management

# 查看所有镜像
docker images

# 创建镜像并启动容器
docker run -di --name MyRabbitMQ -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 5672:5672 -p 15672:15672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:management

- Centos 安装

# 安装 socat  
yum -y install socat
# 下载 erlang
wget http://www.rabbitmq.com/releases/erlang/erlang-19.0.4-1.el7.centos.x86_64.rpm
# 安装erlang 
rpm -ivh erlang-19.0.4-1.el7.centos.x86_64.rpm
# 下载 RabbitMQ
wget  http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.10/rabbitmq-server-3.6.10-1.el7.noarch.rpm
# 安装 RabbitMQ
rpm -ivh rabbitmq-server-3.6.10-1.el7.noarch.rpm

如果 centos 开启了防火墙,则需要开启端口:

# 查看端口是否开启;如果为 no,则执行第二条命令开启端口。
$ firewall-cmd --query-port=15672/tcp
$ firewall-cmd --zone=public --add-port=15672/tcp --permanent
# 开启后要重启防火墙。
$ systemctl restart firewalld.service

管理 UI 和 外部监控插件 rabbitmq_management

# 首先创建目录,否则可能报错:
mkdir /etc/rabbitmq
# 然后启用插件:
rabbitmq-plugins enable rabbitmq_management

- Ubuntu 20.04 安装

sudo apt-get install erlang-nox -y
sudo apt-get update
sudo apt-get install rabbitmq-server -y
    
# 添加用户
sudo rabbitmqctl add_user  admin  admin  

# 赋予权限
sudo rabbitmqctl set_user_tags admin administrator

# 赋予 virtual host 中所有资源的配置、写、读权限
sudo rabbitmqctl  set_permissions -p / admin '.*' '.*' '.*'

管理命令

# 启动 rabbitmq 服务
service rabbitmq-server start

# 关闭 rabbitmq 服务
service rabbitmq-server stop

# 重启 rabbitmq 服务
service rabbitmq-server restart

# 查看 rabbitmq 状态
service rabbitmq-server status

管理 UI 和 外部监控插件 rabbitmq_management

# 启用 rabbitmq_manager
cd /etc/rabbitmq
sudo rabbitmq-plugins enable rabbitmq_management

访问地址:http://localhost:15672

账户:admin

密码:admin

二、 PHP RabbitMQ 客户端(示例:TP5)官方示例地址

Composer 安装

composer require php-amqplib/php-amqplib

添加配置信息 extra\rabbitmq.php

<?php
return [

    'MQ' => [
        'host' => '127.0.0.1',
        'port'=>'5672',
        'login'=>'admin',
        'password'=>'admin',
        'vhost'=>'/'
    ],
    'sms_queue' => [
        'exchange_name' => 'sms_exchange',
        'exchange_type'=>'direct',
        'queue_name' => 'sms_queue',
        'route_key' => 'sms_roteking',
        'consumer_tag' => 'consumer'
    ]
];

生产者 send.php

<?php

namespace app\hive\controller;

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

class Send extends Base
{
    public static function pushMessage($data = "['code' => 1, 'msg' => 'success', 'ts' => time()]")
    {
        $config = config('rabbitmq.MQ');
        $queueConfig = config('rabbitmq.sms_queue');
        $connection = new AMQPStreamConnection( $config['host'], $config['port'], $config['login'], $config['password'], $config['vhost'] );
        $channel = $connection->channel();
        /*
             name: $queue           声明队列
             passive: false
             持久durable: true       队列将在服务器重启后继续存在
             互斥exclusive: false    队列可以通过其他渠道访问
             auto_delete: false     通道关闭后,队列不会被删除
         */
        $channel->queue_declare($queueConfig['queue_name'], false, true, false, false);

        /*
            name: $exchange  声明交换机
            type: direct     直连方式
            passive: false
            durable: true    持久 交换器将在服务器重启后继续存在
            auto_delete: false 一旦通道关闭,交换器将不会被删除。
        */
        $channel->exchange_declare($queueConfig['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, $queueConfig['exchange_name'],$queueConfig['route_key']);
        $channel->close();
        $connection->close();
        echo " [x] Sent 'Hello World!'\n";
    }
}

消费者 receive.php

<?php

namespace app\hive\controller;

use PhpAmqpLib\Connection\AMQPStreamConnection;

class Receive
{
    public function start()
    {
        $config = config('rabbitmq.MQ');
        $amqpDetail = config('rabbitmq.sms_queue');
        $connection = new AMQPStreamConnection( $config['host'], $config['port'], $config['login'], $config['password'], $config['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();
        }
    }

    function shutdown($channel, $connection)
    {
        $channel->close();
        $connection->close();
    }

    function process_message($message)
    {
        echo json_encode($message);

        $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);
        if ($message->body === 'quit') {
            $message->delivery_info['channel']->basic_cancel($message->delivery_info['consumer_tag']);
        }
    }
}

创建命令

<?php

namespace app\v1\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use app\hive\controller\Receive;

class Consumer extends Command
{
    protected function configure()
    {
        $this->setName('consumer') ->setDescription('the consumer command');
    }

    protected function execute(Input $input, Output $output)
    {
        $consumer = new Receive();
        $consumer->start();
    }
}

app\command.php 声明

<?php
return [
    'app\v1\command\Consumer',
];

常用命令

# 查看可以用的操作命令
php think
# 启动消费者
php think consumer

守护进程运行

# nohup表示不挂断地运行命令,&表示在后台运行,两个结合起来使用就可以守护进程运行
nohup php think consumer &
# 如果想关掉,可以先找到这个进程的id,然后杀掉这个进程
# 先找到进程id
ps -ef |grep mailer
# 然后杀掉进程
kill -9 进程id

如有问题请及时反馈。

posted @ 2022-03-01 21:29  孤陌  阅读(400)  评论(0编辑  收藏  举报