1、下载和安装RabbitMQ
官网Messaging that just works — RabbitMQ
docker pull rabbitmq:3-management
docker run \
-e RABBITMQ_DEFAULT_USER=用户名 \
-e RABBITMQ_DEFAULT_PASS=密码 \
--name mq \
--hostname mq1 \
-p 15672:15672 \
-p 5672:5672 \
-d \
rabbitmq:3-management
15672是浏览器访问的端口
5672是应用访问的端口
安装好的界面
登录后的界面
2、安装rabbitmq-c
wget https://github.com/alanxz/rabbitmq-c/archive/v0.10.0.zip
unzip v0.10.0.zip && cd rabbitmq-c-0.10.0
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/rabbitmq-c
cmake --build . --target install
ln -s /usr/local/rabbitmq-c/lib64 /usr/local/rabbitmq-c/lib
3、安装amqp扩展
根据PHP的版本来下载
wget http://pecl.php.net/get/amqp-1.10.0.tgz
tar zxvf amqp-1.10.0.tgz && cd amqp-1.10.0
根据你的PHP版本对应的路径
/www/server/php/74/bin/phpize
./configure --with-php-config=/www/server/php/74/bin/php-config --with-amqp --with-librabbitmq-dir=/usr/local/rabbitmq-c
make && make install
配置php.ini 根据你的扩展安装的路径
extension=/www/server/php/74/lib/php/extensions/no-debug-non-zts-20190902/amqp.so
重启php-fpm或重载配置
查看phpinfo()是否有了amqp
4、PHP代码生产者
简单的一个方法
public function rabbitsend()
{
//配置信息
$conn_args = array(
'host' => 'IP地址',
'port' => '5672',
'login' => 'RabbitMQ安装时的用户名',
'password' => '密码',
'vhost'=>'/'
);
$exchangeName = 'phpcs';
$queueName = 'php_queue1';
$routeKey = 'php_queue1';
$connection = new \AMQPConnection($conn_args);
$connection->connect() or die("Cannot connect to the broker!\n");
# 连接服务
$channel = new \AMQPChannel($connection);
# 创建交换器
$exchange = new \AMQPExchange($channel);
# 设置交换器的名称
$exchange->setName($exchangeName);
# 设置多个参数值[setArguments ( array $arguments )];
# 获取该队列某个参数的信息 , getArgument ( string $key )
# [如果无法将此交换机的消息路由,则将它们发送到这里指定的备用交换机。(设置“alternate-exchange”参数)。]
# 设置交换器类型
# AMQP_EX_TYPE_DIRECT[点对点],AMQP_EX_TYPE_FANOUT[广播],AMQP_EX_TYPE_TOPIC[模糊匹配],AMQP_EX_TYPE_HEADER[头匹配]
$exchange->setType(AMQP_EX_TYPE_DIRECT);
# 交换器持久化
//$exchange->setFlags(AMQP_DURABLE);
# 执行创建交换器
$exchange->declareExchange();
# 创建队列
$queue = new \AMQPQueue($channel);
$queue->setName($queueName);
# 设置单个指定的参数键值,setArgument ( string $key , mixed $value )
# 获取该队列某个参数的信息 , getArgument ( string $key )
//$queue->setArgument();
# [发布到队列中的消息可以在被丢弃之前生存多长时间(毫秒(设置x-message-ttl)参数。]
# [在自动删除队列(毫秒)之前,该队列不能被使用多长时间。(设置“x-expires”参数)。]
# [队列中有多少(准备好的)消息[个数],可以在它开始,从其头上删除之前包含。(设置x-max-length长度)参数]
# [准备好的消息的总大小,队列可以在它开始从头上删除之前包含。(设置x-max-length-bytes 纵向字节)参数]
# [如果拒绝或过期消息将被重新发布的Exchange的可选名称。(设置“x-dead-letter-exchange”参数,[交换器名,(string)])。]
# [可选的替换路由密钥,当消息已被写入字母时使用。如果未设置此消息,将使用消息的原始路由密钥。(设置“x-dead-letter-routing-key”参数)。]
# [支持队列的最大优先级数量;如果未设置,队列将不支持消息优先级。(设置x-max-priority)参数。]
# [将队列设置为懒惰模式,尽可能保留磁盘上的尽可能多的消息以减少RAM的使用;如果没有设置,队列将保持内存中的缓存以尽可能快地传递消息。(设置“x-queue-mode”参数设置:lazy)。]
# [将队列设置为主定位模式,确定在节点群集上声明队列主控器所处的规则。(设置x-queue-master-locator 参数。]
# 设置多个参数值[setArguments ( array $arguments )];
# 获取该队列所有参数的信息 , getArguments ( void )
//$queue->setArguments();
# 持久化队列
# AMQP_DURABLE[队列持久], AMQP_PASSIVE[返回消息计数], AMQP_EXCLUSIVE[只被一个连接(connection)使用,而且当连接关闭后队列即被删除], AMQP_AUTODELETE[当最后一个消费者退订后即被删除].
$queue->setFlags(AMQP_DURABLE);
# 执行创建队列
$queue->declareQueue();
//队列绑定到交换器中
$queue->bind($exchangeName, $routeKey);
# 开启事务,确保数据真正不丢失
$channel->startTransaction();
# 将消息和标识绑定到交换器中
# publish(message[消息],route_key,[ flags[ AMQP_MANDATORY,AMQP_IMMEDIATE],attributes[array] ]);
# attributes 存有参数 => [content_type(用于描述MIME类型的编码。例如,对于经常使用的JSON编码,将此属性设置为 “application/json” 是一个很好的做法。),
#content_encoding,message_id,user_id,app_id,delivery_mode[2 消息持久,1非持久],priority,timestamp,expiration,type,reply_to(主要用于命名一个回调队列 ) ]
//一次生产100条
for($i=1;$i<101;$i++)
{
$message = date("Y-m-d H:i:s") . "Hello PHP:".$i;
$exchange->publish($message,$routeKey);
echo $message."<br>";
}
$channel->commitTransaction();
# 关闭连接
$connection->disconnect();
}
我码的时候遇到一个坑,老是提示“AMQPConnection NOT FOUND”, AMQPConnection这些方法前加了“\”就好了。此处的单个反斜杠就是表示在当前命名空间内调用全局的方法。
效果就是队列一次生成了100条消息
RabbitMQ后台可以看到
5、PHP代码消费者
//消费者
public function rabbituse()
{
//配置信息
$conn_args = array(
'host' => 'IP地址',
'port' => '5672',
'login' => 'RabbitMQ用户',
'password' => '密码',
'vhost'=>'/'
);
$exchangeName = 'phpcs';
$queueName = 'php_queue1';
$routeKey = 'php_queue1';
$connection = new \AMQPConnection($conn_args);
$connection->connect() or die("Cannot connect to the broker!\n");
# 连接服务
$channel = new \AMQPChannel($connection);
$exchange = new \AMQPExchange($channel);
$exchange->setName($exchangeName);
# 设置交换器类型
$exchange->setType(AMQP_EX_TYPE_DIRECT);
# 交换器持久化
//$exchange->setFlags(AMQP_DURABLE);
$exchange->declareExchange();
$queue = new \AMQPQueue($channel);
$queue->setName($queueName);
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue();
# 队列根据routekey 装载消息
$queue->bind($exchangeName,$routeKey);
echo "Message:"."<br>";
$res = $queue->get(AMQP_AUTOACK);
if($res){
echo $res->getbody();
}else{
echo "队列消息为空";
}
}
其实上面2个方法可以整合成类,然后调用,这里为了方便观看和理解就直接写了。
运行效果是这样的
后台就被消费了1条消息。