tp使用abbitmq
1、安装rabbitmq
2、crontab定时检测rabbtimq状态
2、使用thinphp6.0框架rabbitmq示例,supervisor守护消费者
3、RabbitMQ有四种交换机类型
rabbitmq组成部分如下:
Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue。
Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列对消息进行过虑。
Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费方。
Producer:消息生产者,即生产方客户端,生产方客户端将消息发送到MQ。
Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。
消息发布接收流程:
—–发送消息—–
1、生产者和Broker建立TCP连接。
2、生产者和Broker建立通道。
3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
4、Exchange将消息转发到指定的Queue(队列)
—-接收消息—–
1、消费者和Broker建立TCP连接
2、消费者和Broker建立通道
3、消费者监听指定的Queue(队列)
4、当有消息到达Queue时Broker默认将消息推送给消费者。
5、消费者接收到消息。
6、消费者应使用supervisor进行监控保持在线
1、方式一:docker安装RabbitMQ
查看仓库里的RabbitMQ
[root@localhost ~]# docker search rabbitmq
安装RabbitMQ
[root@localhost ~]# docker pull rabbitmq
这里是直接安装最新的,如果需要安装其他版本在rabbitmq后面跟上版本号即可
启动RabbitMQ
[root@localhost ~]# docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq
安装插件
1. 先执行docker ps 拿到当前的镜像ID
[root@localhost ~]# docker ps
2. 进入容器
[root@localhost ~]# docker exec -it 镜像ID /bin/bash
3. 安装web页面插件
[root@localhost ~]# rabbitmq-plugins enable rabbitmq_management
2、方式二:CentOS6.9下安装rabbitmq消息队列
安装如下步骤:
首先安装erlang
[root@localhost ~]# yum install erlang
安装rabbitmq rpm包
[root@localhost ~]# wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.0/rabbitmq-server-3.5.0-1.noarch.rpm
[root@localhost ~]# rpm -ivh rabbitmq-server-3.5.0-1.noarch.rpm
启动rabbitmq
[root@localhost ~]# service start rabbitmq-server
注:如果启动失败,报错如下:
则修改hosts,添加hostname:
[root@localhost ~]# vi /etc/hosts
添加hostname:
再次重启即可:
打开5672端口(注意 15672,5672端口防火墙之类的问题需要开启一下)
[root@localhost ~]# /sbin/iptables -I INPUT -p tcp --dport 5672 -j ACCEPT
[root@localhost ~]# /etc/rc.d/init.d/iptables save
[root@localhost ~]# /etc/init.d/iptables restart
启用web页面插件
[root@localhost ~]# rabbitmq-plugins enable rabbitmq_management
重启rabbitmq
[root@localhost ~]# systemctl start rabbitmq-server
web访问: ip地址可以通过ip add 或者 ifconfig查看
用户名和密码:guest guest
无法登录请使用如下:
[root@localhost ~]# vim /etc/rabbitmq/rabbitmq.config
写入如下信息并保存:
[{rabbit, [{loopback_users, []}]}].
再重启:
再次访问即可:
服务启动
[root@localhost ~]# systemctl start rabbitmq-server.service
看看是否启动成功
[root@localhost ~]# rabbitmqctl status
设置开机自启
[root@localhost ~]# [root@localhost ~]# chkconfig rabbitmq-server on
添加到启动项并设置开机自启
[root@localhost ~]# systemctl enable rabbitmq-server.service
开启管理界面
[root@localhost ~]# rabbitmq-plugins enable rabbitmq_management
添加账号
[root@localhost ~]# rabbitmqctl add_user abc 123456
设置用户角色
[root@localhost ~]# rabbitmqctl set_user_tags abc administrator
设置用户权限
[root@localhost ~]# rabbitmqctl set_permissions -p "/" abc ".*" ".*" ".*"
查看用户和角色 需要启动服务
[root@localhost ~]# rabbitmqctl list_users
删除角色
[root@localhost ~]# rabbitmqctl delete_user Username
2、crontab定时检测rabbtimq状态(应使用supervisor实时监听)
1)crontab定时任务(每分钟检查运行脚本【分,时,日,月,周】)
[root@localhost ~]# crontab -e
...
*/1 * * * * /bin/bash /usr/local/sbin/rabbitmq.sh
2)rabbitmq启动脚本(通过获取pgrep获取rabbitmq-server进程号再进行判断)
[root@localhost ~]# cd /usr/local/sbin
[root@localhost ~]# vim rabbitmq.sh
#!/bin/bash
pgrep -x rabbitmq-server &> /dev/null
if [ $? -ne 0 ]
then
echo "At time: `date` :rabbitmq error stop .">> /var/log/rabbitmqCheck.log
/etc/init.d/rabbitmq-server start
#echo "At time: `date` :rabbitmq server is stop."
else
echo "rabbitmq server is running ." >> /var/log/rabbitmqCheck.log
fi
测试:
1)停止rabbitmq【Active:inactive(dead)】
[root@localhost sbin]# /etc/init.d/rabbitmq-server stop
Stopping rabbitmq-server (via systemctl): [ OK ]
[root@localhost sbin]#
[root@localhost sbin]# systemctl status rabbitmq-server
● rabbitmq-server.service - LSB: Enable AMQP service provided by RabbitMQ broker
Loaded: loaded (/etc/rc.d/init.d/rabbitmq-server; bad; vendor preset: disabled)
Active: inactive (dead) since Wed 2021-01-13 18:01:33 CST; 46s ago
Docs: man:systemd-sysv-generator(8)
Process: 14618 ExecStop=/etc/rc.d/init.d/rabbitmq-server stop (code=exited, status=0/SUCCESS)
Process: 14346 ExecStart=/etc/rc.d/init.d/rabbitmq-server start (code=exited, status=0/SUCCESS)
Jan 13 18:01:02 localhost.localdomain su[14426]: (to rabbitmq) root on none
Jan 13 18:01:02 localhost.localdomain su[14421]: (to rabbitmq) root on none
Jan 13 18:01:05 localhost.localdomain rabbitmq-server[14346]: Starting rabbitmq-server: SUCCESS
Jan 13 18:01:05 localhost.localdomain rabbitmq-server[14346]: rabbitmq-server.
Jan 13 18:01:05 localhost.localdomain systemd[1]: Started LSB: Enable AMQP service provided by RabbitMQ broker.
Jan 13 18:01:29 localhost.localdomain systemd[1]: Stopping LSB: Enable AMQP service provided by RabbitMQ broker...
Jan 13 18:01:29 localhost.localdomain su[14623]: (to rabbitmq) root on none
Jan 13 18:01:30 localhost.localdomain su[14684]: (to rabbitmq) root on none
Jan 13 18:01:33 localhost.localdomain rabbitmq-server[14618]: Stopping rabbitmq-server: rabbitmq-server.
Jan 13 18:01:33 localhost.localdomain systemd[1]: Stopped LSB: Enable AMQP service provided by RabbitMQ broker.
[root@localhost sbin]#
2)隔一分钟再次查看rabbitmq状态【Active:active running】
[root@localhost sbin]# systemctl status rabbitmq-server
● rabbitmq-server.service - LSB: Enable AMQP service provided by RabbitMQ broker
Loaded: loaded (/etc/rc.d/init.d/rabbitmq-server; bad; vendor preset: disabled)
Active: active (running) since Wed 2021-01-13 18:03:04 CST; 35s ago
Docs: man:systemd-sysv-generator(8)
Process: 14618 ExecStop=/etc/rc.d/init.d/rabbitmq-server stop (code=exited, status=0/SUCCESS)
Process: 14917 ExecStart=/etc/rc.d/init.d/rabbitmq-server start (code=exited, status=0/SUCCESS)
Tasks: 2
Memory: 1.4M
CGroup: /system.slice/rabbitmq-server.service
├─14990 /bin/sh /etc/rc.d/init.d/rabbitmq-server start
└─14995 /bin/bash -c ulimit -S -c 0 >/dev/null 2>&1 ; /usr/sbin/rabbitmq-server
Jan 13 18:03:01 localhost.localdomain systemd[1]: Starting LSB: Enable AMQP service provided by RabbitMQ broker...
Jan 13 18:03:01 localhost.localdomain su[14921]: (to rabbitmq) root on none
Jan 13 18:03:02 localhost.localdomain su[14998]: (to rabbitmq) root on none
Jan 13 18:03:02 localhost.localdomain su[14991]: (to rabbitmq) root on none
Jan 13 18:03:04 localhost.localdomain rabbitmq-server[14917]: Starting rabbitmq-server: SUCCESS
Jan 13 18:03:04 localhost.localdomain systemd[1]: Started LSB: Enable AMQP service provided by RabbitMQ broker.
Jan 13 18:03:04 localhost.localdomain rabbitmq-server[14917]: rabbitmq-server.
You have new mail in /var/spool/mail/root
[root@localhost sbin]#
3、thinkphp6.0使用composer安装rabbitmq安装包
本次需要修改的文件有
Comer.php 使用php think生产的命令行
Index.php 测试类
MqConsumer.php 消费者
MqProducer.php 生产者
Console.php 命令行配置项
rabbitmq.php 消息队列配置项
1、安装amqplib
进入到tp6项目根目录安装rabbitmq包,如需忽略版本安装 --ignore-platform-reqs
$composer require --ignore-platform-reqs php-amqplib/php-amqplib
2、在config文件夹下添加rabbitmq.php配置文件
<?php
// 示例配置文件
return [
# 连接信息
'AMQP' => [
'host' => '192.168.1.130', //连接rabbitmq,此为安装rabbitmq服务器
'port'=>'5672',
'login'=>'guest',
'password'=>'guest',
'vhost'=>'/'
],
# 邮件队列
'direct_queue' => [
'exchange_name' => 'direct_exchange',
'exchange_type'=>'direct',#直连模式
'queue_name' => 'direct_queue',
'route_key' => 'direct_roteking',
'consumer_tag' => 'direct'
]
];
3、编写生产者代码
<?php
namespace app\controller;
use app\BaseController;
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.direct_queue');
$connection = new AMQPStreamConnection(
$param['host'],
$param['port'],
$param['login'],
$param['password'],
$param['vhost']
);
$channel = $connection->channel();
/*
* 创建队列(Queue)
* name: hello // 队列名称
* passive: false // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
* durable: true // 是否持久化,设置false是存放到内存中RabbitMQ重启后会丢失,
* 设置true则代表是一个持久的队列,服务重启之后也会存在,因为服务会把持久化的Queue存放在硬盘上,当服务重启的时候,会重新加载之前被持久化的Queue
* exclusive: false // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
* auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
*/
$channel->queue_declare($amqpDetail['queue_name'], false, true, false, false);
/*
* 创建交换机(Exchange)
* name: vckai_exchange// 交换机名称
* type: direct // 交换机类型,分别为direct/fanout/topic,参考另外文章的Exchange Type说明。
* passive: false // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
* durable: false // 是否持久化,设置false是存放到内存中的,RabbitMQ重启后会丢失
* auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
*/
$channel->exchange_declare($amqpDetail['exchange_name'], $amqpDetail['exchange_type'], false, true, false);
/*
* 绑定队列和交换机
* @param string $queue 队列名称
* @param string $exchange 交换器名称
* @param string $routing_key 路由key
* @param bool $nowait
* @param array $arguments
* @param int|null $ticket
* @throws \PhpAmqpLib\Exception\AMQPTimeoutException if the specified operation timeout was exceeded
* @return mixed|null
*/
$channel->queue_bind($amqpDetail['queue_name'], $amqpDetail['exchange_name'], $amqpDetail['route_key']);
/*
$messageBody:消息体
content_type:消息的类型 可以不指定
delivery_mode:消息持久化最关键的参数
AMQPMessage::DELIVERY_MODE_NON_PERSISTENT = 1; 不持久化
AMQPMessage::DELIVERY_MODE_PERSISTENT = 2; 持久化
*/
//将要发送数据变为json字符串
$messageBody = json_encode($data);
/*
* 创建AMQP消息类型
* $messageBody:消息体
* delivery_mode 消息是否持久化
* AMQPMessage::DELIVERY_MODE_NON_PERSISTENT = 1; 不持久化
* AMQPMessage::DELIVERY_MODE_PERSISTENT = 2; 持久化
*/
$message = new AMQPMessage($messageBody, array('content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT));
/*
* 发送消息
* msg // AMQP消息内容
* exchange // 交换机名称
* routing key // 路由键名称
*/
$channel->basic_publish($message, $amqpDetail['exchange_name'],$amqpDetail['route_key']);
$channel->close();
$connection->close();
echo "ok";
}
}
4、消费者代码
<?php
namespace app\controller;
use app\BaseController;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use think\Controller;
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)
{
//休眠两秒
//sleep(2);
echo $message->body."\n";
//自定义日志为rabbitmq-consumer
Log::write($message->body,'rabbitmq-consumer');
//[2021-01-14T16:14:17+08:00][rabbitmq-consumer] {"time":1610612057,"order":85}
//手动发送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();
/*
* 设置消费者(Consumer)客户端同时只处理一条队列
* 这样是告诉RabbitMQ,再同一时刻,不要发送超过1条消息给一个消费者(Consumer),
* 直到它已经处理了上一条消息并且作出了响应。这样,RabbitMQ就会把消息分发给下一个空闲的消费者(Consumer)。
*/
$channel->basic_qos(0, 1, false);
/*
* 同样是创建路由和队列,以及绑定路由队列,注意要跟publisher的一致
* 这里其实可以不用,但是为了防止队列没有被创建所以做的容错处理
*/
$channel->queue_declare($amqpDetail['queue_name'], false, true, false, false);
$channel->exchange_declare($amqpDetail['exchange_name'], $amqpDetail['exchange_type'], false, true, false);
$channel->queue_bind
