rabbitmq实战(广播模式)

RabbitMQ的结构图如下:

 

几个概念说明:

Broker:简单来说就是消息队列服务器实体。

Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。

Queue:消息队列载体,每个消息都会被投入到一个或多个队列。

Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。

Routing Key:路由关键字,exchange根据这个关键字进行消息投递。

vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。

producer:消息生产者,就是投递消息的程序。

consumer:消息消费者,就是接受消息的程序。

channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

消息队列的使用过程大概如下:

(1)客户端连接到消息队列服务器,打开一个channel。

(2)客户端声明一个exchange,并设置相关属性。

(3)客户端声明一个queue,并设置相关属性。

(4)客户端使用routing key,在exchange和queue之间建立好绑定关系。

(5)客户端投递消息到exchange。

exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

exchange也有几个类型,完全根据key进行投递的叫做Direct交换机,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。对key进行模式匹配后进行投递的叫做Topic交换机,符号”#”匹配一个或多个词,符号”*”匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.*”只匹配”abc.def”。还有一种不需要key的,叫做Fanout交换机,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。

RabbitMQ支持消息的持久化,也就是数据写在磁盘上,为了数据安全考虑,我想大多数用户都会选择持久化。消息队列持久化包括3个部分:

(1)exchange持久化,在声明时指定durable => 1

(2)queue持久化,在声明时指定durable => 1

(3)消息持久化,在投递时指定delivery_mode => 2(1是非持久化)

如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。

交换器也有一些性质:

- 持久性:如果启用,交换器将会在协商器重启前都有效。

- 自动删除:如果启用,那么交换器将会在其绑定的队列都被删除掉之后自动删除掉自身。

- 惰性:如果没有声明交换器,那么在执行到使用的时候会导致异常,并不会主动声明。

 拥塞控制

在给出的例子中,对消息的使用永远看做是一个订阅。那么考虑到了拥塞控制吗?规范制定了QoS23特性,限制了通过一个通道发送到一个消费者的消息总量。很不幸的是,这个特性在当前RabbitMQ的版本中还不支持(计划在1.6),但是在原则上是应该被AMQP API支持的。

作为一个替代方案,客户端可以选择从队列中取出消息而不是通过订阅。当使用这种方法的时候,拥塞控制可以手动地实现。


AMQP当中有四个概念非常重要:虚拟主机(virtual host),交换机(exchange),队列(queue)和绑定(binding)。一个虚拟主机持有一组交换机、队列和绑定。为什么需要多个虚拟主 机呢?很简单,RabbitMQ当中,用户只能在虚拟主机的粒度进行权限控制。因此,如果需要禁止A组访问B组的交换机/队列/绑定,必须为A和B分别创 建一个虚拟主机。每一个RabbitMQ服务器都有一个默认的虚拟主机“/”。如果这就够了,那现在就可以开始了。

  • 队列是由消费者(Consumer)通过程序建立的,不是通过配置文件或者命令行工具。
  • 交换机可以理解成具有路由表的路由程序
    • 每个交换机在自己独立的进程当中执行,因此增加多个交换机就是增加多个进程,可以充分利用服务器上的CPU核以便达到更高的效率。
  • 交换机当中有一系列的绑定(binding),即路由规则(routes)



交换机类型
  • Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。
  • Direct Exchange – 处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”,则只有被标记为“dog”的消息才被转发,不会转发dog.puppy,也不会转发dog.guard,只会转发dog。
  • Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。

持久化
队列和交换机有一个创建时候指定的标志durable。durable的唯一含义就是具有这个标志的队列和交换机会在重启之后重新建立,它不表示说在队列当中的消息会在重启后恢复。

消息持久化,当你将消息发布到交换机的时候,可以指定一个标志“Delivery Mode”(投递模式)。根据你使用的AMQP的库不同,指定这个标志的方法可能不太一样。简单的说,就是将 Delivery Mode设置成2,也就是持久的(persistent)即可。一般的AMQP库都是将Delivery Mode设置成1,也就是非持久的。
消息持久化流程:
    将交换机设成 durable。
    将队列设成 durable。
    将消息的 Delivery Mode 设置成2 。

如果你绑定了一个 durable的队列和一个durable的交换机,RabbitMQ会自动保留这个绑定。类似的,如果删除了某个队列或交换机(无论是不是 durable),依赖它的绑定都会自动删除。

RabbitMQ 不允许你绑定一个非坚固(non-durable)的交换机和一个durable的队列。反之亦然。要想成功必须队列和交换机都是durable的。

一旦创建了队列和交换机,就不能修改其标志了。例如,如果创建了一个non-durable的队列,然后想把它改变成durable的,唯一的办法就是删除这个队列然后重现创建。



消费者:接收消息

创建连接-->创建channel-->创建交换机-->创建队列-->绑定交换机/队列/路由键-->接收消息

 '127.0.0.1',   
    'port' => '5672',   
    'login' => 'guest',   
    'password' => 'guest',  
    'vhost'=>'/'  
);    
$e_name = "exchange";
$q_name = "queue1";
$k_route = "route.key";

$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_FANOUT); 
$ex->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
echo "Exchange Status:".$ex->declare()."\n"; 

$q = new AMQPQueue($channel);
$q->setName($q_name);
$q->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
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); 
} 
$conn->disconnect();

function processMessage($envelope, $queue) {  
    $msg = $envelope->getBody();  
    echo $msg."\n";  
    $queue->ack($envelope->getDeliveryTag());
}


生产者:发送消息

创建连接-->创建channel-->创建交换机对象-->发送消息

 '127.0.0.1',   
    'port' => '5672',   
    'login' => 'guest',   
    'password' => 'guest',  
    'vhost'=>'/'  
);    
$e_name = "exchange";
$q_name1 = "queue1";
$q_name2 = "queue2";
$k_route = "route.key";


$conn = new AMQPConnection($conn_args);
if ($conn->connect()) {
echo "Established a connection to the broker \n";
}
else {
echo "Cannot connect to the broker \n ";
}
//你的消息
$message = 'hello word!';
//创建channel
$channel = new AMQPChannel($conn);
//创建exchange
$ex = new AMQPExchange($channel);
$ex->setName($e_name);//创建名字
$ex->setType(AMQP_EX_TYPE_FANOUT);
$ex->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
echo "exchange status:".$ex->declare();
echo "\n";
//创建队列
$q = new AMQPQueue($channel);
//设置队列名字 如果不存在则添加
$q->setName($q_name1);
$q->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
$q->bind($e_name, $k_route);


//创建队列
$q = new AMQPQueue($channel);
//设置队列名字 如果不存在则添加
$q->setName($q_name2);
$q->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
$q->bind($e_name, $k_route);
/*
echo "queue status: ".$q->declare();
echo "\n";
echo 'queue bind: '.$q->bind($e_name, $k_route);//将你的队列绑定到routingKey
echo "\n";
*/
$channel->startTransaction();
for($i=0; $i<5; ++$i){ 
    echo "Send Message:".$ex->publish($message, $k_route)."\n";  
} 
//echo "send: ".$ex->publish($message, $k_route); //将你的消息通过制定routingKey发送
$channel->commitTransaction();
$conn->disconnect();



你可能感兴趣的:(js/shell/php/内核,系统运维)