太坑了!RabbitMQ+PHP开发的辛酸经历

公司需要与另一家公司对接数据,他们指定用RabbitMQ,之前我们也用过MQTT,KAFKA之类的,这个我是第一次接触,想着应该跟kafka差不多,结果过程很不顺利,耽误了一些时间,记录下我的心酸历程。

docker安装RabbitMQ

我现在安装一些环境,基本能用docker就用docker,太方便了。安装比较简单,两个命令搞定:

bash 复制代码
docker pull rabbitmq:3-management
docker run -d --hostname my-rabbit --name rabbit -v /data/rabbitmq:/var/lib/rabbitmq -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672

注释:第二个命令中,--name后面的容器名称可以自定义,-v后面的挂载目录的映射关系也可以根据自己实际情况自定义,同样后面的RABBITMQ_DEFAULT_USER``和RABBITMQ_DEFAULT_PASS,web登录账号密码也可以自定义。运行起来后就可以在浏览器输入 服务器ip:15672访问了,输入上面设置的账号密码即可,非常简单。

安装PHP的amqp扩展

我们想要在PHP中使用RabbitMQ,跟kafka一样,必须要安装相应的扩展,否则程序是运行不起来的。这一步选扩展版本很重要,最新版本是v2.0.0,我就喜欢用最新的版本,但此刻还是建议你用v1.11.0(下面说原因)。此处坑一来了,如果你先直接安装这个扩展,肯定会报以下错误: checking for amqp using pkg-config... configure: error: librabbitmq not found 所以我们要先安装下librabbitmq

bash 复制代码
wget https://github.com/alanxz/rabbitmq-c/archive/v0.9.0.tar.gz
tar -xvf v0.9.0.tar.gz
cd rabbitmq-c-0.9.0
cmake . -DCMAKE_INSTALL_PREFIX=/home/rabbitmq-c-0.9.0 #指定安装目录
make
make install

上述步骤中,如果没有cmake命令,可以安装下yum -y install cmake;安装成功后我们就可以继续安装我们的amqp扩展了。

bash 复制代码
wget https://pecl.php.net/get/amqp-2.0.0.tgz #下载
tar -xvf amqp-2.0.0.tgz #解压
cd amqp-2.0.0
/home/rl/php7.4.33/bin/phpize #用phpize生成编译文件,注意查看你的php在哪里
./configure --with-php-config=/home/rl/php7.4.33/bin/php-config --with-amqp --with-librabbitmq-dir=/home/rabbitmq-c-0.9.0
make && make install

经过上面的操作,我们已经编译生成了amqp.so文件在PHP扩展里了,剩下的就是在php.ini配置中加入extension=amqp.so,重启下php服务就行了,用php -m命令查看下,amqp扩展就有了。下面写个使用例子。

使用PHP写个生产消费的例子

  • 生产者代码:
php 复制代码
<?php
date_default_timezone_set("Asia/Shanghai");
//配置信息 安装RabbitMQ设置的账号密码等
$amqp_config = array( 
    'host' => '你的ip',  
    'port' => '5672',  
    'login' => 'admin',  
    'password' => 'admin', 
    'vhost'=>'/' 
);   
$e_name = 'e_linvo'; //交换机名 
//$q_name = 'q_linvo'; //无需队列名 
$k_route = 'key_1'; //路由key 
 
//创建连接和channel 
$amqp = new AMQPConnection($amqp_config);   
if (!$amqp->connect()) {   
    die("Cannot connect to the broker!\n");   
}   
$channel = new AMQPChannel($amqp);   

//创建交换机对象    
$ex = new AMQPExchange($channel);   
$ex->setName($e_name);   

//发送消息 
//$channel->startTransaction(); //开始事务  
for($i=0; $i<10; ++$i){ 
    //消息内容 
    $message = "$i hello RabbitMQ !";   
    echo "Send Message:".$ex->publish($message, $k_route)."\n";  
} 
//$channel->commitTransaction(); //提交事务 
$amqp->disconnect();

这里就要注意了,坑二来了,执行上面代码,一直报错Cannot connect to the broker!,就是连接的时候代码里抛出的错误,我以为自己设置的账号密码不对,或者安装的RabbitMQ不对,又或者是5672端口没开,调试半天,都还是一直报这个错误,打印连接返回值,发现是null。反正我就觉得不知道什么原因导致的连不上RabbitMQ。后来我想,连接返回值要么是true,要么是false,怎么会是null,只有没有返回值的函数打印才是null,于是我把判断连接的代码注释掉,发现消息正常生产了。 为了验证我的猜想,我去github上看了下扩展的C源码,找到源码里RabbitMQ连接部分,即amqp_connection.c文件。如下图

从上面源码看,连接函数里如果不是持久连接(if里面部分)确实没有返回值,除了该函数上面的有返回值,其他几个函数都是没有写返回值的,所以我们代码里就不能去判断是否连接成功。 既然测试代码里有判断,那肯定之前是有返回值的,我切换了几个版本看了下,发现v2.0系列的都把返回值去掉了,v1.11.0以及之前的版本都是有返回值的,所以上面我会建议还是安装V1.11.0版本的扩展,当然如果不写判断是否连接成功,安装最新版也是没问题的。下面提供下消费端测试代码,感兴趣的同学可以研究下:

php 复制代码
<?php
//配置信息 
$conn_args = array( 
    'host' => '你的ip',  
    'port' => '5672',  
    'login' => 'admin',  
    'password' => 'admin', 
    'vhost'=>'/' 
);   
$e_name = 'e_linvo'; //交换机名 
$q_name = 'q_linvo'; //队列名 
$k_route = 'key_1'; //路由key 
 
//创建连接和channel 
$conn = new AMQPConnection($conn_args);
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); //direct类型  
$ex->setFlags(AMQP_DURABLE); //持久化 
echo "Exchange Status:".$ex->declare()."\n";   
   
//创建队列    
$q = new AMQPQueue($channel); 
$q->setName($q_name);   
$q->setFlags(AMQP_DURABLE); //持久化  
echo "Message Total:".$q->declare()."\n";   
 
//绑定交换机与队列,并指定路由键 
echo 'Queue Bind: '.$q->bind($e_name, $k_route)."\n"; 
 
//阻塞模式接收消息 
echo "Message:\n";   
while(True){ 
    $q->consume('processMessage');   
    //$q->consume('processMessage', AMQP_AUTOACK); //自动ACK应答  
} 
$conn->disconnect();   
 
/**
 * 消费回调函数
 * 处理消息
 */ 
function processMessage($envelope, $queue) { 
    $msg = $envelope->getBody(); 
    echo $msg."\n"; //处理消息 
    $queue->ack($envelope->getDeliveryTag()); //手动发送ACK应答 
}

结语

每次碰到这样的问题,我总是在想,为什么Linux安装环境、测试程序总是会碰到各种各样的问题,就不能顺风顺水,一下就成功吗?转念一想,这不就是我们搬砖人的生活吗?多多积累经验,才会越走越远。

相关推荐
HLC++3 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室4 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy6 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕7 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫8 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生9 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1110 小时前
linux基础IO
linux·运维·服务器
BelongPanda12 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯12 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983412 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器