php 队列 场景,RabbitMQ+PHP php-amqplib使用教程与常用场景-死信队列等

发现网上并没有RabbitMQ PHP客户端的较为详实的使用文档(当然也可能是我搜索引擎使用不熟练?)总之,简单的总结了此文,附录各参数和常用的工作队列,死信队列,以及不同类型交换器的示例,本人水平有限,难免有错误之处,欢迎大佬斧正~

服务器环境 Ubuntu 18.04.5 LTS

PHP 7.2.24

RabbitMQ 3.6.10

php-amqplib 2.7

0.安装(顺手补一下安装过程吧...友好一点点)apt-get install erlang-nox

apt-get install rabbitmq-server

rabbitmqctl add_user admin admin

rabbitmqctl set_user_tags admin administrator

rabbitmqctl set_permissions -p / admin '.*' '.*' '.*'

//开启web管理页面

//cd到安装目录 我这里是/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.10

cd /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.10

rabbitmq-plugins enable rabbitmq_management

cd 到项目目录

composer require php-amqplib/php-amqplib

在需要使用的地方

use PhpAmqpLib\Connection\AMQPStreamConnection;

use PhpAmqpLib\Message\AMQPMessage;

use PhpAmqpLib\Wire\AMQPTable;

1.各方法参数//1.1 建立连接

$conn = new AMQPStreamConnection($host, $port, $user, $password, $vhost);

参数:

$host: RabbitMQ服务器主机IP地址

$port: RabbitMQ服务器端口

$user: 连接RabbitMQ服务器的用户名

$password: 连接RabbitMQ服务器的用户密码

$vhost: 连接RabbitMQ服务器的vhost(服务器可以有多个vhost,虚拟主机,类似nginx的vhost)//1.2 建立信道

$channel = $conn->channel($channel_id);

参数:

$channel_id 信道id,不传则获取$channel[“”]信道,再无则循环$this->channle数组,下标从1到最大信道数找第一个不是AMQPChannel对象的下标,实例化并返回AMQPChannel对象,无则抛出异常No free channel ids//1.3 声明交换器

$channel->exchange_declare($exhcange_name, $type, $passive, $durable, $auto_delete);

参数:

$exhcange_name 交换器名字

$type 交换器类型

$passive 是否检测同名队列

$durable 交换机是否开启持久化

$auto_detlete 通道关闭后是否删除队列

(1)交换器类型

枚举 [

direct: (默认)直接交换器,工作方式类似于单播,Exchange会将消息发送完全匹配ROUTING_KEY的Queue,

fanout: 广播是式交换器,不管消息的ROUTING_KEY设置为什么,Exchange都会将消息转发给所有绑定的Queue,

topic: 主题交换器,工作方式类似于组播,Exchange会将消息转发和ROUTING_KEY匹配模式相同的所有队列,比如,ROUTING_KEY为user.stock的Message会转发给绑定匹配模式为 * .stock,user.stock, * . * 和#.user.stock.#的队列。(* 表是匹配一个任意词组,#表示匹配0个或多个词组),

headers:根据消息体的header匹配

]//1.4 声明队列

$channel->queue_declare($queue_name, $passive, $durable, $exclusive, $auto_delete);

参数:

$queue_name 队列名称

$passive 是否检测同名队列

$durable 是否开启队列持久化

$exclusive 队列是否可以被其他队列访问

$auto_delete 通道关闭后是否删除队列//1.5 创建要发送的信息 ,可以创建多个消息

$msg = new AMQPMessage($data, $properties)

$data 要发送的消息

$properties Array 设置的属性,比如设置该消息持久化['delivery_mode'=>2]

//单个发送

$channel->basic_publish($msg,

$exchange = '',

$routing_key = '',

$mandatory = false,

$immediate = false,

$ticket = null);

参数:

$msg 消息内容

$exchange 交换器

$routing_key routing_key

$mandatory 匹配不到队列时,是否立即丢弃消息

$immediate 队列无消费者时,是否立即丢弃消息

$ticket 这个俺也不知道 坐等大佬

//多个发送

1.多次调用 $channel->batch_basic_publish($msg, $exchange = '', $routing_key = '', $mandatory = false, $immediate = false, $ticket = null)

内部实现:往$this->batch_messages[]塞

2.再调用一次$channel->publish_batch(),完成发送1.6 路由绑定

$channel->queue_bind(

$queue,

$exchange,

$routing_key = '',

$nowait = false,

$arguments = array(),

$ticket = null

)

参数:

$queue 队列名

$exchange 交换器名

$routing_key routing_key

$nowait 同上 俺也不知

$arguments

$ticket1.7 消费消息

$channel->basic_consume(

$queue = '',

$consumer_tag = '',

$no_local = false,

$no_ack = false,

$exclusive = false,

$nowait = false,

$callback = null,

$ticket = null,

$arguments = array()

)

参数:

$queue 队列名

$consumer_tag

$no_local

$no_ack 是否不需要手动ack:true就是不需要ack|false需要手动ack

$exclusive

$nowait

$callback 消息回调函数

$ticket

$arguments1.8 手动ack 示例

$callback = function($msg) {

sleep($msg->body);

echo " [x] Received sleep ", $msg->body, "\n";

$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);

echo " [x] Ack "."\n";

};1.9 限制分发 示例

限制RabbitMQ只发不超过1条的消息给同一个消费者。当消息处理完毕后,有了反馈,才会进行第二次发送。

$channel->basic_qos(null,1,null);

2.常用场景

2.0 无交换器 直接队列

这里也顺手补一下最基础的使用,连接参数作为demo就直接写死了哈~public function send()

{

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');

$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

$msg = new AMQPMessage('Hello World!');

$channel->basic_publish($msg, '', 'hello');

echo " [x] Sent 'Hello World!'\n";

$channel->close();

$connection->close();

}

public function consume()

{

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');

$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {

echo " [x] Received ", $msg->body, "\n";

};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

while(count($channel->callbacks)) {

$channel->wait();

}

}

2.1 工作队列 按消费能力分发生产者和消费者均增加

$channel->basic_qos(null,1,null);

即可。

2.2 fanout广播示例 注册行为例如注册后需要发送欢迎短信和邮件,将注册行为广播至短信和邮件

生产者

//定义交换器

$channel->exchange_declare('register','fanout',false,false,false);

$msg = new AMQPMessage('register event');

$channel->basic_publish($msg, 'register');

注册短信消费者

$channel->exchange_declare('register','fanout',false,false,false);

$channel->queue_declare('register.sms', false, false, false, false);

$channel->queue_bind('register.sms', 'register');

注册邮件消费者

$channel->exchange_declare('register','fanout',false,false,false);

$channel->queue_declare('register.mail', false, false, false, false);

$channel->queue_bind('register.mail', 'register');

2.3 topic类型 模糊匹配示例 日志分级例如我想一个消费者接受所有日志,一个消费者只接收Error级别日志

生产者

//定义交换器

$channel->exchange_declare('log','topic',false,false,false);

$num = rand(0,10);

if ($num%3 == 0) {

$level = 'error';

}elseif($num%3 == 1){

$level = 'warning';

}else{

$level = 'common';

}

$msg = new AMQPMessage('log event '.$level);

$channel->basic_publish($msg, 'log', 'log.'.$level);

全量日志消费者

$channel->exchange_declare('log','topic',false,false,false);

$channel->queue_declare('log.all', false, false, false, false);

$channel->queue_bind('log.all', 'log', 'log.*');

Error日志消费者

$channel->exchange_declare('log','topic',false,false,false);

$channel->queue_declare('log.error', false, false, false, false);

$channel->queue_bind('log.error', 'log', 'log.error');

2.4 headers类型 匹配示例 日志分级例如我想一个消费者接受所有日志,一个消费者只接收Error级别日志

生产者

//定义交换器

$channel->exchange_declare('log2','headers',false,false,false);

$num = rand(0,10);

if ($num%3 == 0) {

$level = 'error';

}elseif($num%3 == 1){

$level = 'warning';

}else{

$level = 'common';

}

$msg = new AMQPMessage('log2 event '.$level);

$bindArguments = [

'level' => $level,

'type' => 'log'

];

$headers = new AMQPTable($bindArguments);

$msg->set('application_headers', $bindArguments);

$channel->basic_publish($msg, 'log2');

全量日志消费者

$channel->exchange_declare('log2','headers',false,false,false);

$channel->queue_declare('log2.all', false, false, false, false);

$bindArguments = [

'type' => 'log',

//'x-match' => 'any' //默认any

];

$headers = new AMQPTable($bindArguments);

$channel->queue_bind('log2.all', 'log2', '', false, $headers);

Error日志消费者

$channel->exchange_declare('log2','headers',false,false,false);

$channel->queue_declare('log2.error', false, false, false, false);

$bindArguments = [

'type' => 'log',

'level' => 'error',

'x-match' => 'all' //默认any

];

$headers = new AMQPTable($bindArguments);

$channel->queue_bind('log2.error', 'log2', '', false, $headers);

2.5死信队列//2.5.1 定义一个没有消费者,5s后消息过期的队列

//生产者

$arguments = new AMQPTable([

'x-dead-letter-exchange' => 'dead',

'x-message-ttl' => 5000, //消息存活时间毫秒

'x-dead-letter-routing-key' => 'dead'

]);

//定义队列 不要交换器

$channel->queue_declare('no_consume', false, false, false, false, false, $arguments);

$now = time();

$msg = new AMQPMessage($now);

$channel->basic_publish($msg, '', 'no_consume');

echo " [x] Sent no_consume :".date('Y-m-d H:i:s',$now)."\n";

$channel->close();

$connection->close();

//消费者

$channel->exchange_declare('dead','topic',false,false,false);

$channel->queue_declare('dead.all', false, false, false, false);

$channel->queue_bind('dead.all', 'dead', 'dead');

$channel->basic_qos(null,1,null);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {

var_dump('msg:'.date('Y-m-d H:i:s',$msg->body));

var_dump('now:'.date('Y-m-d H:i:s'));

echo " [x] Received log error ", $msg->body, "\n";

};

$channel->basic_consume('dead.all', '', false, true, false, false, $callback);

while(count($channel->callbacks)) {

$channel->wait();

}

bVcMSqb

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值