本文所有內(nèi)容均個人從RabbitMQ官網(wǎng)教程中翻譯政钟,若圖片文字的引用有任何侵權(quán)的地方闲先,聯(lián)系我撕氧,我會立馬刪除。
This article was translated from RabbitMQ Official Tutorials by myself核行,and if this article and the images in this article have any infringement,please contact to me, and i will delete them.
話題
(使用php-amqplib)
在上一個教程我們升級了我們的日志系統(tǒng)牢硅。與僅僅能夠進(jìn)行虛擬廣播的fanout
類型交換機(jī)不同,我們使用了一個direct
類型交換機(jī)芝雪,并獲得了可以選擇性地接收日志的能力减余。
盡管使用direct
交換機(jī)提升我們的系統(tǒng),但它仍然是由限制的——它不能夠在多個標(biāo)準(zhǔn)下進(jìn)行路由惩系。
在我們的日志系統(tǒng)中位岔,我們可能希望不僅僅是根據(jù)日志等級來訂閱日志如筛,也可以根據(jù)發(fā)送日志的源。你可能已經(jīng)從可以同時根據(jù)日志的嚴(yán)重性(info
/warn
/crit
....)與設(shè)施(auth
/cron
/kern
...)來路由日志的Unixsyslog
工具知道這一概念抒抬。
這會帶給我們非常多的靈活性——我們可能打算僅僅監(jiān)聽來自cron
的嚴(yán)重錯誤日志而又監(jiān)聽來自kern
的所有日志杨刨。
為了在我們的日志系統(tǒng)實現(xiàn)這一公功能,我們需要學(xué)習(xí)一個更加復(fù)雜的topic
交換機(jī)
Topic交換機(jī)
消息發(fā)送到一個topic
交換機(jī)不能隨意設(shè)置routing_key
——它必須是一系列以點分隔的詞擦剑。這些詞可以是隨意的妖胀,但它們通常指定了消息的一些特性。有一些有效的路由鍵(routing key)的例子:'stock.usd.nyse'
惠勒,nyse.vmw
赚抡,quick.orange.rabbit
。他們可以由很多你喜歡的路由鍵組成纠屋,最多不能超過255個字節(jié)(bytes)涂臣。
綁定鍵(binding key)也必須是同樣的格式。topic
交換機(jī)的邏輯與direct
交換機(jī)是相似的——一條攜帶特定路由鍵(routing key)發(fā)送的消息將會被分發(fā)到所有以與之匹配的綁定鍵(binding key)綁定的Queue(隊列)售担。然而赁遗,關(guān)于綁定鍵,有兩個需要特別注意的情況:
- *(星號)可以代替(任意)一個詞灼舍。
-
(井號)可以代替零個或者更多的詞
這是一個最簡單的解釋例子:
在這一個例子中吼和,我們準(zhǔn)備發(fā)送一些描述動物的消息涨薪。這些消息被發(fā)送時將會帶有由三個單詞組成(兩個點)的路由鍵(routing key)骑素。路由鍵(routing key)的第一個詞將會描述速度,第二個描述顏色刚夺,第三個描述物種:'<speed>.<colour>.<species>'
献丑。
我們創(chuàng)建了三個綁定:Q1
隊列以'*.orange.*
路由鍵綁定,Q2
以'*.*.rabbit
與lazy.#
(兩個路由鍵)綁定侠姑。
這些綁定可以概括為:
Q1
對所有orange(橙色)的動物感興趣创橄。
Q2
想監(jiān)聽rabbit(兔子)的所有消息與lazy(慢吞吞的)動物的所有消息。
一條路由鍵(routing key)被設(shè)置為'quick.orange.rabbit
的消息將會被交付到這兩個隊列莽红。路由鍵為'lazy.orange.elephant'
的消息也會被交付到這兩個隊列妥畏。而另一種路由鍵為'quick.orange.fox'
的消息只會去到第一個(Q1
)隊列,以及'lazy.brown.fox'
只會發(fā)送到第二個(Q2
)隊列安吁。路由鍵為lazy.pink.rabbit
的消息只會被發(fā)送到第二個(Q2
)隊列一次醉蚁,盡管它符合兩個綁定。'quick.brown.fox'
不匹配任何一個綁定鬼店,所以它會被丟棄网棍。
如果我們打破我們的規(guī)定,發(fā)送了一條只帶有一個詞或者帶有四個詞的路由鍵的消息妇智,例如'orange'
或者'quick.orange.male.rabbit'
滥玷,會發(fā)生什么呢氏身?這些消息將不會匹配到任何綁定上并且將會被丟失。
在另一方面惑畴,盡管'lazy.orange.male.rabbit'
擁有四個詞蛋欣,它將會匹配最后一個綁定(lazy.#
),并將會發(fā)送到第二個隊列如贷。
話題交換機(jī)(Topic Exchange)
話題交換機(jī)是十分強大的豁状,同時它能表現(xiàn)得想其他的交換機(jī)一樣。
當(dāng)一個Queue(隊列)以"#"
(井號)綁定鍵(binding key)綁定——它將會忽視路由鍵(routing key)去接收所有消息就像是一個fanout
類型的交換機(jī)一樣倒得。當(dāng)特殊字符
"*"
(星號)與"#"
(井號)沒有被用在綁定(鍵)上泻红,這時候topic
交換機(jī)由表現(xiàn)得像direct
交換機(jī)一樣。
把他們一起運行
我們準(zhǔn)備在我們的日志系統(tǒng)中使用一個topic
交換機(jī)霞掺。我們將從一個工作假設(shè)開始谊路,即日志的路由鍵將有兩個單詞:"<facility>.<severity>"
。
代碼與上一個教程的十分相似菩彬,
emit_log_topic.php
的代碼如下:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// 聲明一個topic交換機(jī)
$channel->exchange_declare('topic_logs', 'topic', false, false, false);
// 從命令行獲取路由鍵
$routing_key = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'anonymous.info';
$data = implode(' ', array_slice($argv, 2));
if(empty($data)) $data = "Hello World!";
$msg = new AMQPMessage($data);
// 攜帶路由鍵發(fā)送到topic_logs交換機(jī)
$channel->basic_publish($msg, 'topic_logs', $routing_key);
echo " [x] Sent ",$routing_key,':',$data," \n";
$channel->close();
$connection->close();
?>
receive_logs_topic.php
的代碼如下:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// 聲明topic交換機(jī)
$channel->exchange_declare('topic_logs', 'topic', false, false, false);
// 獲取非持久化隊列
list($queue_name, ,) = $channel->queue_declare("", false, false, true, false);
$binding_keys = array_slice($argv, 1);
if( empty($binding_keys )) {
file_put_contents('php://stderr', "Usage: $argv[0] [binding_key]\n");
exit(1);
}
// 綁定多個綁定鍵到隊列
foreach($binding_keys as $binding_key) {
$channel->queue_bind($queue_name, 'topic_logs', $binding_key);
}
echo ' [*] Waiting for logs. To exit press CTRL+C', "\n";
$callback = function($msg){
echo ' [x] ',$msg->delivery_info['routing_key'], ':', $msg->body, "\n";
};
$channel->basic_consume($queue_name, '', false, true, false, false, $callback);
while(count($channel->callbacks)) {
$channel->wait();
}
$channel->close();
$connection->close();
?>
如果想接收所有日志:
php receive_logs_topic.php "#"
接收"kern"設(shè)備的所有日志:
php receive_logs_topice.php "kern.*"
或者你只想監(jiān)聽"critical"
的日志:
php receive_logs_topic.php "*.critical"
你可以創(chuàng)建多個綁定:
php receive_logs_topic.php "kern.*" "*.critical"
以及缠劝,發(fā)送一個帶有"kern.critical"
路由鍵的日志請輸入:
php emit_log_topic.php "kern.critical" "A critical kernel error"
用這些程序愉快地玩耍吧。要主意的是骗灶,這些代碼是沒有對路由或綁定鍵做任何的假設(shè)惨恭,你可能希望使用兩個兩個以上的路由鍵參數(shù)。