RabbitMQ+php

参考https://www.cnblogs.com/zxxyx/p/6202306.html

 

rabbittmq简介

一、常见的几种消息队列的比较

实际上,这个地方摘抄的,也不知道啥意思,就集中写在这里吧,万一哪天看懂了呢

https://blog.csdn.net/qq_35688140/article/details/102903589

1,activemq

  • 具有优秀的api,是sun公司提出的jms规范的一种消息队列
  • 不适合高并发场合,性能不足,适合中小型架构;

两种模式:master-slave模式 和 network模式

在这里插入图片描述

2,kafka

  • 速度高:使用操作系统为memory mapper files方式,完成操作系统虚拟内存的作用,从而实现到内存地址的映射在这里插入图片描述

3,rocketmq

  • 对kafka的事务性和可靠性传输做了优化
  • 商业版收费

nameserver就是相当于zookeeper,由于zookeeper太慢了,所以使用name server,几百行代码实现了name server。

在这里插入图片描述

4,rabbitmq

  • 速度慢于kafka,快于activemq
  • 良好的事务性

架构

在这里插入图片描述

-------------------------------------------------------------------------------------------

 

二、rabbitmq常见的五种模式

摘抄    https://blog.csdn.net/m0_37968982/article/details/103985291

按照投递规则和消费方式的不同,主要有5种常见的模式。

1,简单模式:simple/helloworld单生产单消费

投递规则:队列名称和routing key相同

原理:

生产者将消息交给默认的交换机,交换机获取消息后交给绑定这个生产者的队列,监听当前队列的消费者获取信息并执行消费逻辑。

场景:

有一个oa系统,用户接收手机验证码进行注册,页面上点击获取验证码后,将验证码放到消息队列,然后短信服务从队列中获取验证码,并发送给用户。

2,工作模式:work单发送多接收

原理:

生产者将消息交给交换机,交换机交给绑定的队列,队列有多个消费者监听,一条消息只能由一个消费者消费,这样就形成了资源竞争,谁的资源空闲大,争抢到的可能性就大。

场景:

有一个电商平台,有两个订单服务,用户下单的时候,任意一个订单服务消费用户的下单请求生成订单即可。不用两个订单服务同时消费用户的下单请求。

备注:保证资源竞争的代码为:channel.basicQos(1),告诉服务器,在消费者没有确认当前消息时,不要再发送新的消息。如果没有这行代码,消费者是轮询消费消息的。

3,发布订阅模式:public/subsribe

原理:

生产者将消息扔给交换机,交换机类型为fanout,不同的队列注册到交换机上,不同的消费注册在不同的队列上。所有消费者都会收到消息。

场景:

商城,添加一个商品后,可能同时需要去更新缓存和数据库。

注意:交换机没有保存消息的功能,如果没有消费者,则消息对丢失。

问题:为何这句话写这里呢?前几个不也存在这个问题么?

4,路由模式:routing

原理:

生产者将消息发送给交换机,消息携带具体的routingkey。交换机类型是direct,接收到消息中的routingkey,比对与之绑定的队列的routingkey,分发到不同的队列上。

场景:

商城中,新添加一个商品,实时性不是很高,值需要将其添加到数据库即可,不用刷新缓存。

5,主题(通配符)模式:topics,按topic发送接收

原理:

路由模式的一种,路由功能添加了模糊匹配。

星号*代表一个单词,# 代表一个或多个单词。

场景:

商城中,新添加一个产品,实时性不是很高,只需要添加到数据库即可,数据库包含了主库和从库,不用刷新缓存。

 

------------------------------------------------------实操环节到了-----------------------------------------------------------

 

rabbitmq+php

一、ubuntu下rabbitmq安装:

1,安装erlang

由于rabbitmq需要erlang语言的支持,所以安装rabbitmq之前先安装erlang

sudo apt-install erlang-nox

2,安装rabbitmq

#更新源
sudo apt-get update

#安装
sudo apt-get install rabbitmq-server

启动、停止、重启和状态rabbitmq命令

sudo rabbitmq-server start 
sudo rabbitmq-server stop
sudo rabbitmq-server restart
sudo rabbitmqctl status

3,添加admin并赋予administrator权限

添加admin用户,密码设置为admin

#添加admin用户,密码设置为admin
sudo rabbitmqctl add_user admin admin

#赋予权限
sudo rabbitmqctl set_user_tags admin administrator

#赋予virtual host中所有资源的配置、写读权限以便管理其中的资源--不太懂,抄录一遍
sudo rabbitmqctl set permissions -p /admin.'*'.'*'.'*'

4,rabbitmq guid使用

1)官方提供的一个web管理工具(rabbitmq_management)

https://www.rabbitmq.com/management.html

2)安装了rabbitmq之后,默认页安装了该管理工具,执行命令即可启动

sudo rabbitmq-plugins enable rabbitmq_management

二、rabbitmq+php

 

上面的安装,其实我整完都乱七八糟的,运行自己的代码老报错误,原因就是扩展没安装成功,我也不知道咋回事。

咨询同事,他也是各种失败,最后找我们公司专门负责我们开发环境的老师安装的,他给我发了一份文件,一键式即可安装。

如下:

1)一份压缩包,拷贝到自己虚拟机上。

这里没法上传,需要的人可以联系我,等我上传到网盘上,再补充链接,那边有点问题,暂时上传不上去。

2)依次执行如下命令即可:

tar zxvf amqp-package.tar.gz

cd amqp-package

./install.sh

注意:最后的这个shell脚本也会上传到网盘上,之后补充。

内容就是下载,安装编译配置啥的。内容先粘贴出来:

apt-get update
apt-get install -y cmake
tar zxvf amqp-1.9.3.tgz
unzip rabbitmq-c-master.zip
cd rabbitmq-c-master
mkdir build && cd build
cmake ..
cmake --build .
make
make install
cd ../../
cd amqp-1.9.3
phpize
./configure --with-amqp
make 
make install

echo "extension=amqp.so" > /etc/php5/mods-available/amqp.ini
php5enmod amqp

cd ..
rm -r amqp-1.9.3
rm -r rabbitmq-c-master
 
php -m|grep amqp

 

-----------------------------------------------------------------------------------------------------------------------------------

 

rabbitmq是一个流行的开源消息队列系统,用erlang语言开发,完整的实现了AMQP(高级消息队列协议)。

rabbitmq启动默认是没有任何配置的,需要客户端连接上去,设置交换机等才能工作。

step1: vhosts:虚拟主机

一个rabbitmq server为一个消息队列服务器实体(broker),可以有多个用户,而用户只能在虚拟主机的粒度进行权限控制,所以,rebbitmq需要有多个虚拟机主机,每个rabbitmq服务器都有个默认的虚拟机主机'/'。对于一般的php应用,不需要用户权限设定,直接使用默认的 '/'即可,用户可以使用默认存在的'guest',例如:

$configs = array(
    'host'=>'127.0.0.1',
    'port'=>'5672',
    'login'=>'guest',
    'password'=>'guest',
    'vhost' =>'/'
);

 

step2: connection与channel:连接与通信

connection是指物理的连接,一个client与一个server之间有一个连接,一个连接上可以建立多个channel,可以理解为逻辑上的连接。一般情况下,有一个channel就够了,不需要创建更多的channel.

//创建连接和channel
$conn = new AMQPConnection($configs);
if(!$conn->connect()){
    die('cannot connect to the broker\n');
}
$channel = new AMQPChannel($configs);

step3: exchange与routingkey:交换机与路由键

为了将不同类型的消息进行区分,设置了交换机与路由两个概念。比如将A类型的消息发送到名为C1的交换机,将B类型的消息发送到名为C2的交换机。当客户端连接C1处理队列消息时,取到的就是只有A类型的消息。

进一步,如果A类型的消息也非常多,需要进一步细化区分,比如某个客户端只处理A类型消息中针对K用户的消息,routingkey就是用来做这个用途的。

//交换机名
$e_name= 'e_linvo';
//路由key
$k_route = array(0=>'key_1',1=>'key_2');
//创建交换机
$ex = new AMQPExchange($channel);
$ex->setName($e_name);
$ex->setType(AMQP_EX_TYPE_DIRECT);//direct类型
$ex->setFlags(AMQP_DURABLE);//持久化
$message = 'hello world';
echo 'Exchange Status'.$ex->declare().'\n';
for($i=0;$i<5;$i++){
    echo 'send message: '.$ex->publish($message,$k_route[$i%2]).'\n';
}

 

由以上代码可以看到,发送消息的时候,只要有交换机就足够了至于交换机后main有没有对应的处理队列,发送方是不用管的。routingkey可以是空的字符串。在示例中,我们使用了两个key交替发送消息,是为了更便于理解routingkey的作用。

对于交换机,有两个重要的给概念:

A . 类型

有三种类型:

  • fanout类型最简单,这种模型忽略routingkey,只看exchange。
  • direct类型是使用最多的,使用确定的exchange和routingkey。在这种模型下,接收消息时绑定key_1,则只接收key_1的消息。
  • topic,与direct类似,但是支持通配符进行匹配。比如,key_*就会接收key_1和key_2,虽然看着美好但是可能导致不严谨,还是推荐使用direct。

比如,交换机类型使用常见的direct类型,则只要消息队列的exchange与routekey同发送方的exchange和routekey一样,就能接收到消息,不用管消息队列名称两边是否一样。

具体可见链接:

http://blog.sina.com.cn/s/blog_8ff955df0102yyww.html

 

B. 持久化

指定了持久化的交换机,在重新启动时才能重建,否则需要客户端重新声明生成才行。

需要特别明确的概念:交换机的持久化,并不等于消息的持久化。只有在持久化队列中的消息,才能持久化;如果没有队列,消息是没有地方存储的;消息本身在投递时也有一个持久化标志的,php中默认投递到持久化交换机就是持久的消息,不用特别指定。

step4:queue:队列

事实上,队列仅是针对接收方(consumer)的,由接收方根据需求创建的。只有队列创建了,交换机才会将新接收到的消息送到队列中,交换机是不会将在队列创建之前的消息放进来的。也就是,在建立队列之前,发出的所有消息都被丢弃了。

疑问:如果发布东西,需要重新启动队列,在启动过程中,会重新创建队列,即使名字一样,但是这个中间差的消息被丢弃了?????

注意,队列属于receive mesage部分。

下面代码为创建队列和接收消息的实例。

//
$e_name = 'e_linvo';//交换机名
$q_name = 'q_linvo';//队列名
$k_route = '';//路由key

//创建链接和channel
$conn = new AMQPConnection($configs);
if(!$conn->connect()){
    die('cannot connect to the broker \n');
}
$channel = new AMQPChannel($conn);
$ex = new AMQPExchange($channel);
$ex->setName($e_name);
$ex->setType(AMQP_EX_TYPE_DIRECT);
$ex->setFlags(AMQP_DURABLE);
echo 'exchange status'.$ex->declare().'\n';

//创建队列
$q = new AMQPQueue($channel);
$q->setName($q_name);
$q->setFlags(AMQP_DURABLE); //持久化

//绑定交换机与队列,并指定路由键
echo 'queue bind:'.$q->bind($e_name,$k_route).'\n';

//阻塞模式接收消息
echo 'message \n';
$q->consume('processMessage',AMQP_AUTOACK);//自动ack应答
$conn->disconnect();


/*
 * 消费回掉函数
 * 处理消息
 **/
function processMesage($envelope,$queue){
    var_dump($envelope->getRoutingKey);//这个函数不清楚对不对
    $msg = $envelope->getBody();
    echo $msg.'\n'; //处理的消息内容
}

从示例可以看到,交换机既可以由消息发送端创建,也可以由消息消费者创建。

创建一个队列后,需要将队列绑定到交换机上,队列才能工作。routingkey也是在这里指定的。

消息的处理是有两种方式:

A.一次性

用$q->get([......]),不管取到取不到消息都会立即返回,一般情况下使用轮询处理消息队列就要用这种方式;

B.阻塞

用$q->consume(callback, [.....])程序会进入持续侦听状态,每收到一个消息就会调用callback指定的函数一次,直到某个callback函数返回false才结束。

关于callback,php支持数组,比如 $c = new MyClass(); $c->counter = 100; $q->consume( array($c,'myfunc') ),这样就可以调用自己写的处理类,其中myfunc的参数与例子中的processMessage一样就行。

注意,在上面的实例中,$k_route为空,意味接收全部的消息。我们可以改为 $k_route='key_1',则结果中仅有设置routingkey为key_1的内容。

 

 

 

 

在程序设计上,需要规划好exchange的名称,以及如何使用key区分开不同类型的标记,在消息产生的地方插入发送消息代码。

后端处理,可以针对每一个key启动一个或者多个client,以提高消息处理的实时性。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值