异步队列rabbitmq

安装
yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel

安装erlang

cd /usr/src
#wget http://erlang.org/download/otp_src_18.2.1.tar.gz
tar -xvf otp_src_18.2.1.tar.gz 
cd otp_src_18.2.1
./configure 
# make clean
make install

安装rabbitmq-server

cd /usr/src
#wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.9/rabbitmq-server-generic-unix-3.6.9.tar.xz    
#yum install xz
tar -xvf rabbitmq-server-generic-unix-3.6.9.tar
cp -r rabbitmq_server-3.6.9 /usr/local/rabbitmq

修改环境变量

vim /etc/profile
#最后一行加上
export PATH=/usr/local/rabbitmq/sbin:$PATH   
#然后执行
source /etc/profile

开放端口后台管理端口

iptables -I INPUT -p tcp --dport 15672 -j ACCEPT

启动

rabbitmq-plugins enable rabbitmq_management   #启动后台管理
rabbitmq-server -detached #启动服务

权限配置

# 删除guest
rabbitmqctl delete_user guest
#添加用户admin
rabbitmqctl add_user admin admin
#设置用户admin的角色
#角色
#administrator  超级管理员
#none 不能访问统计插件
#management 访问本用户的统计插件
#policymaker 访问本用户的统计插件 以及查看、创建和删除自己的virtual hosts
#monitoring  访问本用户以及其他用户统计插件
rabbitmqctl set_user_tags admin administrator
#设置用户admin权限
#-p / 指定虚拟机/
rabbitmqctl set_permissions  -p /  admin ".*" ".*" ".*" 
常用命令
#启动
rabbitmq-server -detached
#关闭 是指关闭rabbitmq监听端口5672 
#rabbitmqctl stop [<pid_file>]
rabbitmqctl stop 
#启用应用 停止消费队列和发送信息等等操作
start_app
#关闭应用 开启消费队列和发送信息
stop_app
#启用插件
rabbitmq-plugins enable **** 
#关闭插件
rabbitmq-plugins disable **** 
###################################
#队列
#vhost为虚拟机  是一种路径分组分割
#rabbitmqctl list_queues [-p <vhost>]
rabbitmqctl list_queues -p /test
#查看队列未确认的消费信息
rabbitmqctl list_queues name messages_ready messages_unacknowledged
#交换器
#list_exchanges [-p <vhost>]
#查看绑定的队列
#list_bindings [-p <vhost>] 
#查看信息通道
list_channels
#虚拟机###########################################################
#查看虚拟机
rabbitmqctl list_vhosts
#添加虚拟机
#rabbitmqctl add_vhost 虚拟机
rabbitmqctl add_vhost test
#删除虚拟机
#rabbitmqctl delete_vhost vhost_one
rabbitmqctl delete_vhost test
#用户###########################################################
#查看用户列表
rabbitmqctl list_users
#查看用户权限
#rabbitmqctl list_user_permissions 用户名
rabbitmqctl list_user_permissions admin
#添加用户
#rabbitmqctl add_user 用户名 密码
rabbitmqctl add_user admin admin
#修改密码
#change_password 用户名 新密码
rabbitmqctl change_password  admin password
#删除用户
#rabbitmqctl delete_user 用户名
rabbitmqctl delete_user guest
 #设置用户为管理员
 #rabbitmqctl set_user_tags 用户名 administrator
 rabbitmqctl set_user_tags admin administrator
#设置用户权限
#rabbitmqctl set_permissions -p / 用户名 ".*" ".*" ".*"
使用

安装php-amqplib

composer require  php-amqplib/php-amqplib  ~2.8.0

流程

主要有两个脚本组成 一个发布 一个消费 可以位于不同主机上

发布 是指将消息对象发布到交换器上 可以指定匹配路由

消费 是指对队列的消费 消费的单元是一个个消息对象
建立一个队列 然后将队列绑定到交换器进行消费

扫描二维码关注公众号,回复: 4574566 查看本文章

名词说明

信息通道channel : 异步队列本身就是进程间通信 多个进程消息对象处理中心 发布和消费位于不同主机上 有点类似协议

交换器 :是指信息通道是对消息对象的存储单元
路由 在交换器上的指定消费条件 以便队列绑定到指定路由上进行消费
交换方式主要有fanout direct topics
fanout 是一种群播方式 不指定路由
direct 是指定路由
topics是指定路由匹配模式
路由匹配模式是按照.号进行分割单词 其中*匹配一个单词#匹配0个到多个单词
例如 下面三种路由匹配模式
test.*.*
*.test2.*
test3.#
队列 test.test3.test2 将匹配第一个
队列 test.test2.test3 将匹配第一个和第二个
队列 test3.test2.test 将匹配第二个和第三个

函数介绍

//初始化===========================================================
//连接rabbitmq
$connection = new AMQPStreamConnection('主机', '端口', '用户名', '密码','虚拟机');
//建立通道
$channel = $connection->channel();
//定义一个交换器
$channel->exchange_declare('交换器', '交换模式');
//消息对象===========================================================
//消息属性
//delivery_mode: 将消息标记为持久化 是指将消息保存在硬盘上
//持久化array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
//非持久化array('delivery_mode' => AMQPMessage::DELIVERY_MODE_NON_PERSISTENT)
//content_type: 消息MIME类型 
//reply_to: 处理回执信息的标识符
//correlation_id: 该消息的连接唯一标识符 用来处理回执信息时候需要验证是不是同一个连接
//消息属性数组
$option=array('reply_to'=>'repHander','delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
'content_type'=>'text/plain','correlation_id'=> uniqid()
);
//建立消息对象
$msg = new AMQPMessage('消息body',$option);
//队列===========================================================
//定义一个队列
//$channel->queue_declare($name='',$passive = false,$durable = false,$exclusive = false,$auto_delete = true,$nowait = false,$arguments)
//name队列名 如果为空 会自动生成一个队列名 返回值的第一个元素就是队列名
//durable是否为持久化消息
//exclusive是否为独占消息 如果被一个通道占用 则其他通道无法消费该消息
//auto_delete 是否自动删除 消息一旦被消费 立即删除 为false则需要等待消息确认才删除
//nowait 是否为非阻塞
//arguments 队列相关的参数---------- 
//x-max-length 队列最大长度
//x-max-length-bytes 队列最大字节数
//x-message-ttl 消息生存时长 单位 毫秒
//x-expires 队列生存时长 单位 毫秒
//x-max-priority 消息优先级 1-10
$arguments=array('x-max-length'=>10000)
list($queue_name,,) = $channel->queue_declare('', false, false, true, false,false,$arguments)
//将队列绑定到路由上
$channel->queue_bind(队列名,交换器,路由模式);
$channel->queue_bind($queue_name,'exchange','key1.#');

//队列发布	
$channel->basic_publish(消息对象, '交换器名', '路由名');
//队列消费分配
//$channel->basic_qos($prefetch_size, $prefetch_count)
//prefetch_size 每次消费字节数 
//prefetch_count 每次消费的消息对象的个数
$channel->basic_qos(NULL, 1,NULL)
//队列消费
//$channel->basic_consume($queue_name,$consumer_tag = '',$no_local = false,$no_ack = false,$exclusive = false,$nowait = false,$callback=null)
//queue_name 队列名
//no_ack  是否为不需要确认的队列
//exclusive 是否为独占队列
//nowait 是否阻塞队列
//callback 消息对象的回调处理函数
$channel->basic_consume($queue_name, '', false, false, false, false, $callback);
//回调处理===========================================================
//通道中异步回调数组	
$channel->callbacks	
$callback = function($req) {
//消息正文 $req->body
//投递消息路由 $req->delivery_info['routing_key']
//投递消息通道 $req->delivery_info['channel']
//投递消息标签 $req->delivery_info['delivery_tag']
//消息确认 告诉发布者消息已经处理完成 可以删除该消息
$req->delivery_info['channel']->basic_ack($req->delivery_info['delivery_tag']);
//获取消息属性
//投递消息连接id $rep->get('correlation_id')
//投递消息回执处理队列名 $rep->get('reply_to')
};
#建个测试用户test
rabbitmqctl add_user test test
rabbitmqctl set_user_tags test none
rabbitmqctl add_vhost /test
rabbitmqctl set_permissions -p /test test ".*" ".*" ".*" 

发布脚本 pulish.php

$connection = new AMQPStreamConnection('localhost', 5672, 'test', 'test','/test');
$channel = $connection->channel();
$channel->exchange_declare('exchange','topic');
$option=array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
'content_type'=>'text/plain'
);
$msg = new AMQPMessage('Hello test!',$option);
$channel-> basic_publish($msg,'exchange','key1.key2.key3');
$channel->close();
$connection->close();

消费脚本 consume.php


$connection = new AMQPStreamConnection('localhost', 5672, 'test', 'test','/test');
$channel = $connection->channel();
$channel->exchange_declare('exchange','topic');
list($queue_name,,) = $channel->queue_declare();
$channel->queue_bind($queue_name,'exchange','key1.#');
$channel->basic_qos(NULL, 1,NULL);
$callback = function($req) {
	echo '消息正文:'.$req->body.PHP_EOL;
$req->delivery_info['channel']->basic_ack($req->delivery_info['delivery_tag']);
};

$channel->basic_consume($queue_name, '', false, false, false, false, $callback);
while(count($channel->callbacks)) {
    $channel->wait();
}
$channel->close();
$connection->close();

需要回执的消息对象 远程调用rpc
发布脚本 pulish.php

$connection = new AMQPStreamConnection('localhost', 5672, 'test', 'test','/test');
$channel = $connection->channel();
$channel->exchange_declare('exchange','topic');
$correlation_id=uniqid();
$reply_to='reply';
//处理回执消息=================================
$response='';
list($queue_name,,)=$channel->queue_declare();
$channel->queue_bind($queue_name,'exchange',$reply_to);
$channel->basic_qos(NULL,1,NULL);
$callback = function($req)use($correlation_id,&$response){
	//检查回执的连接id是否发送者生成连接id一致
	 if($req->get('correlation_id') == $correlation_id) {
		 //获取回执消息正文
            $response=$req->body;
			echo $response;
        }		
$req->delivery_info['channel']->basic_ack($req->delivery_info['delivery_tag']);
};
$channel->basic_consume($queue_name, '', false, false, false, false, $callback);
//发布===============================================
$option=array('reply_to'=>$reply_to,'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
'content_type'=>'text/plain','correlation_id'=> $correlation_id
);
$msg = new AMQPMessage('Hello test!',$option);
$channel-> basic_publish($msg,'exchange','key1.key2.key3');
 while(!$response){
    $channel->wait();
} 
$channel->close();
$connection->close();

消费脚本 consume.php

$connection = new AMQPStreamConnection('localhost', 5672, 'test', 'test','/test');
$channel = $connection->channel();
$channel->exchange_declare('exchange','topic');
list($queue_name,,) = $channel->queue_declare();
$channel->queue_bind($queue_name,'exchange','key1.#');
$channel->basic_qos(NULL,1,NULL);
$callback = function($req) {	
	$msg='处理后的消息:'.$req->body;
	//发送消息============
	 $msgobj = new AMQPMessage(
        $msg,
        array('correlation_id' => $req->get('correlation_id'))
        );
    $req->delivery_info['channel']->basic_publish(
        $msgobj, 'exchange', $req->get('reply_to'));
	$req->delivery_info['channel']->basic_ack($req->delivery_info['delivery_tag']);
};

$channel->basic_consume($queue_name, '', false, false, false, false, $callback);
while(count($channel->callbacks)) {
    $channel->wait();
}
$channel->close();
$connection->close();

消费队列可以是多线程消费的

猜你喜欢

转载自blog.csdn.net/qq_38984126/article/details/83817478
今日推荐