RabbitMQ队列,php实现

相关资料

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 

   RabbitMQ队列,php实现_第1张图片

  重新启动

  

php-5.5 扩展amqb 1.2

php.ini

php amqb扩展RabbitMQ队列,php实现_第2张图片

一 概念

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秒中

查看相关状态

队列结束,访问正常

RabbitMQ队列,php实现_第3张图片

接收还在处理

RabbitMQ队列,php实现_第4张图片

 查看服务器还有多少队未处理 rabbitmqctl list_queues

查看数据库数据,mysql,表类型myisam 还在添加中

RabbitMQ队列,php实现_第5张图片


这应该是典型的 使用队列的场景了


总结,以上只是简单的处理,实际上在生产环境中,还有许多要处理的。

有了这个可以处理抢购程序,有时间可以再试下redis的队列。

不过 RabbitMQ 还有不少没研究的,继续努力……




你可能感兴趣的:(PHP,rabbitmq,Queue,AMQP)