相关资料
rabbitmq官网 http://www.rabbitmq.com/
php amqb扩展安装 http://blog.csdn.net/chhxo/article/details/6695055
环境安装
rabbitmq-server服务器端 4.x
#导入erlang源,并安装erlang rpm --import http://binaries.erlang-solutions.com/debian/erlang_solutions.asc wget http://apt.sw.be/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt rpm -i rpmforge-release-0.5.2-2.el6.rf.*.rpm yum update yum update --skip-broken yum install erlang wget -c http://www.rabbitmq.com/releases/rabbitmq-server/v3.3.0/rabbitmq-server-3.3.0-1.noarch.rpm yum install rabbitmq-server-3.3.0-1.noarch.rpm
启动命令
/etc/init.d/rabbitmq-server start
查看状态 端口号5672
常用命令
rabbitmqctl status 查看状态
启用插件
rabbitmq-plugins enable rabbitmq_management
重新启动
php-5.5 扩展amqb 1.2
php.ini
一 概念
RabbitMQ是一个消息代理。它的核心原理非常简单:接收和发送消息。你可以把它想像成一个邮局:你把信件放入邮箱,邮递员就会把信件投递到你的收件人处。在这个比喻中,RabbitMQ是一个邮箱、邮局、邮递员。RabbitMQ和邮局的主要区别是,它处理的不是纸,而是接收、存储和发送二进制的数据——消息。
RabbitMQ使用的是AMQP协议。要使用她你就必须需要一个使用同样协议的库。几乎所有的编程语言都有可选择的库
二 简单实现
发送 send
<?php /** * PHP amqp(RabbitMQ) Send */ $exchangeName = 'demo'; $queueName = 'hello'; $routeKey = 'hello'; $message = 'Hello World!'; $connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest')); $connection->connect() or die("Cannot connect to the broker!\n"); try { $channel = new AMQPChannel($connection); $exchange = new AMQPExchange($channel); $exchange->setName($exchangeName); $queue = new AMQPQueue($channel); $queue->setName($queueName); $exchange->publish($message, $routeKey); var_dump("Amqp Sent 'Hello World!'"); } catch (AMQPConnectionException $e) { var_dump($e); exit(); } $connection->disconnect();
执行
php amqpSend.php 输出 Amqp Sent 'Hello World!'
接收
<?php /** * PHP amqp(RabbitMQ) Receive */ $exchangeName = 'demo'; $queueName = 'hello'; $routeKey = 'hello'; $connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest')); $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->declare(); $queue = new AMQPQueue($channel); $queue->setName($queueName); $queue->declare(); $queue->bind($exchangeName, $routeKey); var_dump(' Waiting for messages. To exit press CTRL+C'); while (TRUE) { $queue->consume('callback'); } $connection->disconnect(); function callback($envelope, $queue) { $msg = $envelope->getBody(); var_dump(" [x] Received:" . $msg); $queue->nack($envelope->getDeliveryTag()); }
php amqpReceive.php string(46) "[*] Waiting for messages. To exit press CTRL+C" string(26) " [x] Received:Hello World!"
二 并发实现测试
比如系统的中的日志往往很多,有的写入比较耗时,有的错误日志比较重要,需要发邮件,这个比较耗时等。这时候尝试用amqp来处理,最佳实践中不一定是 amqp, 可能redis队列比较适合
写个简单的例子,修改接收的程序比较耗时,加入数据库操作,看能否在高并发时把所有的数据加入库
修改 receive程序
<?php /** * PHP amqp(RabbitMQ) Receive */ $dbhand = null; conn(); $exchangeName = 'demo'; $queueName = 'hello'; $routeKey = 'hello'; $connection = new AMQPConnection(array('host' => '127.0.0.1', 'port' => '5672', 'vhost' => '/', 'login' => 'guest', 'password' => 'guest')); $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->declare(); $queue = new AMQPQueue($channel); $queue->setName($queueName); $queue->declare(); $queue->bind($exchangeName, $routeKey); var_dump('[*] Waiting for messages. To exit press CTRL+C'); while (TRUE) { $queue->consume('callback'); } $connection->disconnect(); function callback($envelope, $queue) { $msg = $envelope->getBody(); var_dump(" [x] Received:" . $msg); insert($msg); $queue->nack($envelope->getDeliveryTag()); } function conn(){ global $dbhand; $dsn = "mysql:host=127.0.0.1;dbname=test"; try{ $dbhand = new PDO($dsn, "root", ''); }catch(PDOexception $e){ var_dump($e->getMessage()); exit; } } function insert($msg){ global $dbhand; usleep(100000); // 0.1秒 $addtimestr = date('Y-m-d H:i:s', time()); $sql = "INSERT INTO `test`.`amqp`(`msg`, `addtimestr`) VALUES('$msg', '$addtimestr') "; if( $dbhand->exec($sql) ){ var_dump('Log Id Is '.$dbhand->lastinsertid()); }else{ var_dump('Insert Error'); } return true; }
开启服务端接收任务, php amqpReceive.php
我们使用 http_load 来测试并发下
./http_load -p 100 -seconds 300 urls.txt 100个进程, 30秒中
查看相关状态
队列结束,访问正常
接收还在处理
查看服务器还有多少队未处理 rabbitmqctl list_queues
查看数据库数据,mysql,表类型myisam 还在添加中
这应该是典型的 使用队列的场景了
总结,以上只是简单的处理,实际上在生产环境中,还有许多要处理的。
有了这个可以处理抢购程序,有时间可以再试下redis的队列。
不过 RabbitMQ 还有不少没研究的,继续努力……