路由(Routing)
在
前面的教程中,我们实现了一个简单的日志系统。可以把日志消息广播给多个接收者。
本篇教程中我们打算新增一个功能——使得它能够只订阅消息的一个字集。例如,我们只需要把严重的错误日志信息写入日志文件(存储到磁盘),但同时仍然把所有的日志信息输出到控制台中
绑定(Bindings)
前面的例子,我们已经创建过绑定(bindings),代码如下:
1 | $exchange ->publish( $message , '' ); |
绑定(binding)是指交换器(exchange)和队列(queue)的关系。可以简单理解为:这个队列(queue)对这个交换器(exchange)的消息感兴趣。
绑定的时候可以带上一个额外的routing_key参数。为了避免与basic_publish的参数混淆,我们把它叫做bindingkey。以下是如何创建一个带bindingkey的绑定。
1 | $exchange ->publish( $message , $routeKey ); |
bindingkey的含义取决于交换器(exchange)的类型。我们之前使用过的fanout类型会忽略这个值。
Direct类型的交换器(exchange)
我们的日志系统广播所有的消息给所有的消费者(consumers)。我们打算扩展它,使其可以能够精确的过滤消息。例如我们也许值是希望当接收到一个严重的错误的时候才把消息写入磁盘,以免浪费磁盘空间。
我们使用的fanout类型的交换器(exchange)扩展性不够——它能做的仅仅是广播。
我们将会使用direct类型的交换器(exchange)来代替。路由的算法很简单——交换器将会对bindingkey和routingkey进行精确匹配,从而确定消息该分发到哪个队列。
下图能够很好的描述这个场景:
在这个场景中,我们可以看到directexchangeX和两个队列绑定了。第一个队列使用orange作为bindingkey,第二个队列有两个绑定,一个使用black作为bindingkey,另外一个是green。
这样以来,当routingkey为orange的消息发布到交换器(exchange),就会被路由到队列Q1。routingkey为black或者green的消息就会路由到Q2。其他的所有消息都将会被丢弃。
多个绑定(Multiplebindings)
多个队列使用相同的bindingkey是合法的。我们的这个例子,我们可以添加一个X和Q1之间的绑定,使用blackbindingkey。这样一来,direct交换器就和fanout交换器的行为一样,将会广播消息到所有匹配的队列。带有routingkey为black的消息都会发送到Q1和Q2。
Emittinglogs
我们将会发送消息到一个directexchange,把日志级别作为routingkey。这样子负责处理接收的脚本就可以选择它要处理的日志级别。我们先看看触发日志。
我们需要创建一个交换器(exchange):
1 | $exchange ->setName( 'direct_logs' ); |
然后我们发送一则消息:
1 | $exchange ->publish( $message , $severity ); |
我们先假设“severity”的值是info、warning、error中的一个。
订阅(Subscribing)
处理接收消息的方式和之前差不多,但是我们为每一个日志级别创建了一个新的绑定。
1 | foreach ( $severities
as $item ){ |
2 | $queue ->bind( $exchangeName , $item ); |
整合
emit_log_direct.py的代码:
04 | *PHPamqp(RabbitMQ)Demo-4 |
05 | *@authoryuansir<yuansir@live.cn/yuansir-web.com> |
07 | $severity = count ( $argv )>2?
$argv [1]: 'info' ; |
08 | $message =
empty ( $argv [2])?
'HelloWorld!' : ''
. $argv [2]; |
10 | $connection =
new AMQPConnection( array ( 'host'
=> '127.0.0.1' , 'port' => '5672' , 'vhost' => '/' , 'login' => 'guest' , 'password' => 'guest' )); |
11 | $connection ->connect() or die ( "Cannotconnecttothebroker!\n" ); |
13 | $channel =
new AMQPChannel( $connection ); |
14 | $exchange = new AMQPExchange( $channel ); |
15 | $exchange ->setName( 'direct_logs' ); |
16 | $exchange ->setType(AMQP_EX_TYPE_DIRECT); |
19 | $exchange ->publish( $message , $severity ); |
20 | var_dump( "[x]Sent$message" ); |
22 | $connection ->disconnect(); |
receive_logs_direct.py的代码:
04 | *PHPamqp(RabbitMQ)Demo-4 |
05 | *@authoryuansir<yuansir@live.cn/yuansir-web.com> |
07 | $exchangeName =
'direct_logs' ; |
09 | $connection =
new AMQPConnection( array ( 'host'
=> '127.0.0.1' , 'port' => '5672' , 'vhost' => '/' , 'login' => 'guest' , 'password' => 'guest' )); |
10 | $connection ->connect() or die ( "Cannotconnecttothebroker!\n" ); |
11 | $channel =
new AMQPChannel( $connection ); |
12 | $exchange = new AMQPExchange( $channel ); |
13 | $exchange ->setName( $exchangeName ); |
14 | $exchange ->setType(AMQP_EX_TYPE_DIRECT); |
16 | $queue =
new AMQPQueue( $channel ); |
17 | $queue ->setFlags(AMQP_EXCLUSIVE); |
24 | var_dump( "Usage:$file[info][warning][error]" ); |
27 | foreach
( $severities as $item ){ |
28 | $queue ->bind( $exchangeName , $item ); |
32 | var_dump( '[*]Waitingformessages.ToexitpressCTRL+C' ); |
34 | $queue ->consume( 'callback' ); |
36 | $connection ->disconnect(); |
38 | function callback( $envelope , $queue ){ |
39 | $msg
= $envelope ->getBody(); |
40 | var_dump( '[x]'
. $envelope ->getRoutingKey().
':' . $msg ); |
41 | $queue ->nack( $envelope ->getDeliveryTag()); |
如果你希望只是保存warning和error级别的日志到磁盘,只需要打开控制台并输入:
1 | $phpreceive_logs_direct.phpwarningerror& gt ;logs_from_rabbit.log |
如果你希望所有的日志信息都输出到屏幕中,打开一个新的终端,然后输入:
1 | $phpreceive_logs_direct.phpinfowarningerror |
2 | [*]Waiting
for logs.To exit
pressCTRL+C |
如果要触发一个error级别的日志,只需要输入:
1 | $phpemit_log_direct.phperror "Run.Run.Oritwillexplode." |
2 | [x]Sent
'error' : 'Run.Run.Oritwillexplode.' |
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理