RabbitMQ是一个基于Erlang实现的消息队列服务,遵循AMQP通信协议,是比较流行通用的异步消息队列服务。
(背景知识,Erlang是一个结构化,动态类型编程语言,内建并行计算支持。使用Erlang编写的程序通常有许多轻量级进程组成,通过消息传递互相通信,进程间上下文切换比C的线程切换高效地多。)
首先下载安装Erlang,然后下载rabbitmq的rpm安装包(我的环境是fedora 14),执行下面的命令安装服务
[root@fedora Projects]# rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
[root@fedora Projects]# yum install rabbitmq-server-2.8.2-1.noarch.rpm
可能还需要下载一些erlang的依赖包,安装有点慢,不过yum会帮我们搞定这些。安装完毕后可以启动服务了
[root@fedora Projects]# service rabbitmq-server start
Starting rabbitmq-server: SUCCESS
rabbitmq-server.
[root@fedora Projects]#
然后接着安装php的扩展包,我在rabbitmq的官网上找了一个
php-amqplib,安装方法如下:
git clone git://github.com/videlalvaro/php-amqplib.git
cd php-amqplib/
make
这个扩展并不是提供一个动态链接库,而是提供了一些头文件的封装,我们先进入demo目录来测试一下能否正常运行(如果遇到下面这个错误,需要安装php-bcmath扩展)
[root@fedora demo]# php amqp_consumer.php
PHP Fatal error: Call to undefined function PhpAmqpLib\Wire\bcmod() in /home/fedora/Projects/php-amqplib/PhpAmqpLib/Wire/AMQPWriter.php on line 34
安装完php-bcmath后再运行php amqp_consumer.php
[root@fedora demo]# php amqp_consumer.php
程序在此处挂起等待生产者发布消息,然后我们打开另外一个终端模拟生产者
[root@fedora demo]# php amqp_publisher.php some text to publish
然后再看消费者,已经拿到消息如下:
--------
some text to publish
--------
再测试发送消息如下,则消费者程序退出。可以看出php的扩展包已经可以正常运行了。
[root@fedora demo]# php amqp_publisher.php quit
下面我们来看看代码中是怎么用的吧,首先程序需要包含两个基本的头文件,都是在demo目录下
autoload.php
<?php
require_once(__DIR__ . '/../vendor/symfony/Symfony/Component/ClassLoader/UniversalClassLoader.php');
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
'PhpAmqpLib' => __DIR__ . '/..',
));
$loader->register();
config.php
<?php
include_once(__DIR__.'/autoload.php');
define('HOST', 'localhost');
define('PORT', 5672);
define('USER', 'guest');
define('PASS', 'guest');
define('VHOST', '/');
//If this is enabled you can see AMQP output on the CLI
define('AMQP_DEBUG', false);
消费者的代码如下:
<?php
include(__DIR__ . '/config.php');
use PhpAmqpLib\Connection\AMQPConnection;
$exchange = 'router';
$queue = 'msgs';
$consumer_tag = 'consumer';
/**
* 生产者消费者一样的代码
*/
$conn = new AMQPConnection(HOST, PORT, USER, PASS, VHOST);
$ch = $conn->channel();
$ch->queue_declare($queue, false, true, false, false);
$ch->exchange_declare($exchange, 'direct', false, true, false);
$ch->queue_bind($queue, $exchange);
/**
* 注册消息回调函数
*/
function process_message($msg) {
echo "receive message : " . $msg->body . "\n";
$msg->delivery_info['channel']->
basic_ack($msg->delivery_info['delivery_tag']);
}
$ch->basic_consume($queue, $consumer_tag, false, false, false, false, 'process_message');
/**
* 关闭连接回调
*/
function shutdown($ch, $conn){
$ch->close();
$conn->close();
}
register_shutdown_function('shutdown', $ch, $conn);
/**
* 循环等待消息
*/
while (count($ch->callbacks)) {
$ch->wait();
}
?>
生产者的代码如下:
<?php
include(__DIR__ . '/config.php');
use PhpAmqpLib\Connection\AMQPConnection;
use PhpAmqpLib\Message\AMQPMessage;
$exchange = 'router';
$queue = 'msgs';
/**
* 生产者消费者一样的代码
*/
$conn = new AMQPConnection(HOST, PORT, USER, PASS, VHOST);
$ch = $conn->channel();
$ch->queue_declare($queue, false, true, false, false);
$ch->exchange_declare($exchange, 'direct', false, true, false);
$ch->queue_bind($queue, $exchange);
/**
* 发布消息到消息队列
*/
$msg_body = "hello consumer";
$msg = new AMQPMessage($msg_body, array('content_type' => 'text/plain', 'delivery_mode' => 2));
$ch->basic_publish($msg, $exchange);
$ch->close();
$conn->close();
?>
分别执行消费者和生产者,我们可以看到消费者端获取到了“hello consumer”的文本信息
此外,看上面创建队列,创建连接的参数很多,可以进行比较详细的个性化定制。rabbitmq虽然功能强大,在软件领域里面得到很多的应用,可是针对互联网的应用场景可能还是redis可以更好地胜任。所以同样是作为消息队列,两者也是各有所长。官方有提供各种语言版本的扩展支持,python的代码感觉要简单得多,我找的这个php的扩展使用起来还是麻烦了点,如果是提供动态链接库的扩展方式就好了。