公司需要与另一家公司对接数据,他们指定用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安装环境、测试程序总是会碰到各种各样的问题,就不能顺风顺水,一下就成功吗?转念一想,这不就是我们搬砖人的生活吗?多多积累经验,才会越走越远。