來源於官方手冊(通俗易懂) https://www.rabbitmq.com/tutorials/tutorial-one-php.html
1. Hello World / Simple /簡單 模式
生產者:send.php
<?php
/**
* Simple 模式 - 生產者
* RabbitMq 6種模式
* Date: 2020/4/20 下午4:15
*/
require_once __DIR__. '/../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
//創建一個 連接 到 RabbitMq服務器
//注意 協議版本
$connection = new AMQPStreamConnection('192.168.8.234', 5672, 'guest', 'guest');
//創建一個channel,大多數 API 都要使用它來做一些事情。
$channel = $connection->channel();
//爲了發送,我們必須聲明 一個隊列queue 來發送
//聲明隊列 是冪等性的,隊列只在它不存在的時候創建
$channel->queue_declare(
'hello',
false,
false,
false,
false
);
//消息的內容是 字節數組 格式,所以你可以 對其進行編碼(encode)
$msg = new AMQPMessage('Hello World:');
$channel->basic_publish(
$msg,
'', //交換機名稱
'hello' //路由key
);
echo " [x] Sent 'Hello World!'\n";
//關閉channel
$channel->close();
//關閉連接
$channel->close();
receive.php
<?php
/**
* Simple 模式 - 消費者
* RabbitMq 6種模式
* Date: 2020/4/20 下午4:15
*/
require_once __DIR__. '/../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
// 不像生產者(publisher),消費者receiver 爲了接收消息 需要監聽(listening) RabbitMQ
$connection = new AMQPStreamConnection('192.168.8.234', 5672, 'guest', 'guest');
$channel = $connection->channel();
//注意, 這裏也聲明瞭隊列(queue),因爲這個消費者啓動的程序 可能 早於生產者程序的啓動,
//在這裏也聲明爲了確保,在我們試着從它裏邊消費時,這個隊列是存在的。
$channel->queue_declare(
'hello',
false,
false,
false,
false
);
//記住,消息被server 異步發送給 client(消費端)的
//需要定義一個 回調函數, 參數是 消息
$callback = function ($msg) {
echo ' [x] Received ', $msg->body, "\n";
};
//
$channel->basic_consume(
'hello',
'',
false,
true,
false,
false,
$callback
);
//不論何時,我們接收到了消息,我們將調用 $callback 函數,參數爲"消息"
while ($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();
2、 工作隊列模式 Work Queue
【消息丟失】
在沒有ack 情況下 像 一個任務 執行需要幾秒鐘,如果一個worker 被kill 或者其他服務器問題,這個worker 接收的這個消息被沒有被正確處理, 而在隊列裏邊 它已經被標記爲for deletion。這樣情況 這個消息就丟了
爲了 確保 一個消息 永不丟失,RabbitMQ 支持 消息確認(message acknowledgments)
【消息確認機制】
//如果一個 消費者 consumer 死掉了(他的channel 被關閉,connection被關閉,或者 tcp連接斷了),這時它沒有發送 一個 ack RabbitMQ 將理解爲 這個消息沒有被完全處理,將重新把它放到 隊列裏。如果這時候,有其他的 消費者在線,它將很快將此消息投遞給其他的消費者。
注意:不存在 消息 超時時間,即便是 處理一個消息需要非常長非常長的時間。
【忘記確認】
這是常見的錯誤,後果很嚴重。由於它不能夠釋放任何沒被確認的消息,它將佔用越來越多的內存。
爲了能夠找出 這種類型 的錯誤。使用命令:
//sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
消息的持久性 (durability)
當 RabbitMQ quit 或者宕機,它會丟掉 隊列或消息 除非你告訴它不要這樣。
爲了消息不丟失。 我們需要做2件事,標記隊列 和 消息 都爲 持久化(durable)
1. 這個 durable =true 的標誌,需要生產者 和消費者 都去設置
2. 在AMQPMessage 中 設置 delivery_mode=2
【注意消息的 持久化!】
標記消息爲 持久化,不能夠完全 保證消息不丟失。因爲這裏存在很短的時間窗口:當RabbitMQ收到消息還沒有保存。 // RabbitMQ 不會針對每個消息 來進行 fsync, 他會先保存到 緩存裏。 // 這種持久機制 不是強壯的,但是對於簡單的任務隊列是足夠了。如果你需要一個更加強壯的保障機制, // 你可以使用 publisher_confirms.
【注意】:RabbitMQ 不允許你 使用不同的參數 去重新定義一個 已經存在的 隊列queue,如果這樣做了,它將返回一個錯誤error
【公平的分發】
默認地: RabbitMQ 它 不看 消費者的未確認消息的數量,它僅僅不加思考地 分發每一個 n-th 消息到 n-th 消費者。
爲了改變這種分發策略! 可以使用 basic_qos 設置 prefetch_count=1;
// 含義是:不要分發 一個新消息給 一個消費者 除非它已經處理並確認了之前的一個消息。
$channel->basic_qos(null, 1, null);
new_task.php 代碼如下:
<?php
/**
* workerQueue 模式 - 生產者
* 這種模式與 simple沒有本質的區別(代碼層面的)它加上了持久化,公平分發等參數,啓用多個worker 來模擬真正的工作上的用法
* 基於此原因,生產環境中不要使用simple例子中的代碼
* RabbitMq 6種模式
* Author: zhaozhiliang
* Email: [email protected]
* Date: 2020/4/20 下午4:15
*/
require_once __DIR__. '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
//創建一個 連接 到 RabbitMq服務器
//注意 協議版本
$connection = new AMQPStreamConnection('192.168.21.234', 5672, 'guest', 'guest');
//創建一個channel,大多數 API 都要使用它來做一些事情。
$channel = $connection->channel();
//爲了發送,我們必須聲明 一個隊列queue 來發送
//聲明隊列 是冪等性的,隊列只在它不存在的時候創建
$channel->queue_declare(
'task_queue', //前一個 hello
false,
true, //持久化 false
false,
false
);
//消息的內容是 字節數組 格式,所以你可以 對其進行編碼(encode)
$data = implode(' ', array_slice($argv, 1));
if (empty($data)) {
$data = "Hello World!";
}
$msg = new AMQPMessage(
$data,
array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT) //想讓消息持久化必須進行此設置
);
$channel->basic_publish(
$msg,
'', //交換機名稱
'task_queue' //路由key ; 之前爲task_queue
);
echo " [x] Sent ", $data, "\n";
//關閉channel
$channel->close();
//關閉連接
$channel->close();
//默認地
// RabbitMQ 將 按照順序地 發送每個消息 給 下一個 消費者;
// 平均每個消費者 將得到 相同數量的消息。這種分發消息的方式 叫 round-robin (輪詢)
/**
* //運行結果 -shell1
[root@liang workQueues]# php new_task.php First message.
[x] Sent First message.
[root@liang workQueues]# php new_task.php Second message..
[x] Sent Second message..
[root@liang workQueues]# php new_task.php Third message...
[x] Sent Third message...
[root@liang workQueues]# php new_task.php Fourth message....
[x] Sent Fourth message....
[root@liang workQueues]# php new_task.php Fifth message.....
[x] Sent Fifth message.....
// shell2
[x] Received Second message..
[x] Done
[x] Received Fourth message....
[x] Done
// shell3
[x] Received First message.
[x] Done
[x] Received Third message...
[x] Done
[x] Received Fifth message.....
[x] Done
*
*
*/
worker.php 代碼如下:
<?php
/**
* Simple 模式 - 消費者
* RabbitMq 6種模式
* Author: zhaozhiliang
* Email: [email protected]
* Date: 2020/4/20 下午4:15
*/
require_once __DIR__. '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
// 不像生產者(publisher),消費者receiver 爲了接收消息 需要監聽(listening) RabbitMQ
$connection = new AMQPStreamConnection('192.168.21.234', 5672, 'guest', 'guest');
$channel = $connection->channel();
//注意, 這裏也聲明瞭隊列(queue),因爲這個消費者啓動的程序 可能 早於生產者程序的啓動,
//在這裏也聲明爲了確保,在我們試着從它裏邊消費時,這個隊列是存在的。
$channel->queue_declare(
'task_queue', //之前爲hello
false,
true, //之前爲false
false,
false
);
//假的任務 消耗的時間,一個點一秒鐘
$callback = function ($msg) {
echo ' [x] Received ', $msg->body, "\n";
sleep(substr_count($msg->body, '.'));
echo " [x] Done\n";
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
$channel->basic_qos(
null,
1, //不要分發 一個新消息給 一個消費者 除非它已經處理並確認了之前的一個消息。
null
);
//
$channel->basic_consume(
'task_queue', //之前爲hello
'',
false,
false, //true 不確認; false 確認
false,
false,
$callback
);
//不論何時,我們接收到了消息,我們將調用 $callback 函數,參數爲"消息"
while ($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();
3、發佈訂閱模式Publish/Subscribe
投遞一個消息給 多個消費者。
模式被叫做 發佈/訂閱 “publish/subscribe”
爲了說明這個模式 。我們將 構建一個 簡單的 日誌系統。
發佈日誌 消息 將廣播給 所有 消費者receivers
一個 消費者 worker 記錄日誌到 硬盤; 另一個消費者 worker 打印日誌到 屏幕上。
RbbitMQ 的消息模式裏面,生產者從來 不要直接發送 任何消息到一個 隊列queue.
替代地, 生產者可以 發送消息 到 exchange.
exchange 決定 發送給哪個 隊列。
exchange 的類型 有 direct, topic, headers , fanout.
列出 exchanges
sudo rabbitmqctl list_exchanges
default exchange 默認exchange
在之前的教程中,我們不知道exchanges,但是 仍然能夠發送消息給 隊列queues.
這個很可能是因爲: 我們正在使用一個默認的 exchange, 它 被定義 使用 空字符串“”
臨時隊列
1 。不論何時 我們連接到 Rabbit 我們需要一個 新的,空的 隊列。爲了做到這樣,
我們可以創建一個隊列,使用隨機的名字,更好的方式是 讓 rabbitmq server 來選擇一個隨機的名字
,我們來用。
2 。 一旦 我們 斷開連接, 消費者隊列 應該被 自動地刪除。
list($queue_name, ,) = $channel->queue_declare("");
名字可能像:amq.gen-JzTY20BRgKO-HjmUJj0wLg
當聲明它的連接 關閉時, queue 將被 關閉,因爲 它被聲明爲 exclusive
綁定:
已經創建了一個 fanout類型的 exchange 和 一個 queue, 現在
我們需要告訴 exchage 去 發送 消息 給 我們的 queue
$channel->queue_bind($queue_name, 'logs');
相關命令:
列出存在的綁定。
rabbitmqctl list_bindings
生產者代碼:emit_log.php
<?php
/**
* Author: zhaozhiliang
* Date: 2020/4/21 下午3:46
*/
require_once __DIR__. '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
//創建一個 連接 到 RabbitMq服務器
$connection = new AMQPStreamConnection('192.168.21.234', 5672, 'guest', 'guest');
//創建一個channel,大多數 API 都要使用它來做一些事情。
$channel = $connection->channel();
$channel->exchange_declare('logs', 'fanout', false,false, false);
$data = implode('', array_slice($argv, 1));
if (empty($data)) {
$data = "info: Hello World!";
}
$msg = new AMQPMessage($data);
$channel->basic_publish($msg, 'logs');
echo ' [x] Sent ', $data, "\n";
$channel->close();
$connection->close();
如果exchange還沒有綁定隊列,這些消息將被 丟失 。不過這個對我們來說還 ok了,
因爲沒有 消費者正在監聽
消費者代碼:receive_logs.php
<?php
/**
* Author: zhaozhiliang
* Date: 2020/4/21 下午4:29
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('192.168.21.234', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->exchange_declare('logs', 'fanout', false, false, false);
list($queue_name, ,) = $channel->queue_declare("", false, false,true, false);
$channel->queue_bind($queue_name, 'logs');
echo " [*] Waiting for logs. To exit press CTRL+C\n";
$callback = function ($msg) {
echo ' [x] ', $msg->body, "\n";
};
$channel->basic_consume($queue_name, '', false, true, false, false, $callback);
while ($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();
如果你想保存日誌 到文件:
php receive_logs.php > logs_from_rabbit.log
如果你想 在屏幕上 看到日誌輸出:
php receive_logs.php
生產者。
php emit_log.php
爲了 解決 如何 去 監聽 一個 消息的子集,看 教程4
4. 路由模式
在前面日誌的系統的基礎上,增加功能。
如: 只有 嚴重錯誤的 消息 才記錄到 硬盤上,另一方面打印 所有的日誌信息到控制檯上。
綁定:
$channel->queue_bind($queue_name, 'logs');
可以簡單地讀: 此queue 對 exchange 上的消息 感興趣
第三個參數: binding key
binding key 含義 取決於 exchange 類型
對於 fanout 類型 exchange。 我們可以簡單的忽略掉 此參數(不傳遞)
Direct 類型 exchange
fanout 類型的 exchange ,這種不能給我們 更多的 靈活性,它只是 簡單的廣播
type =direct ; 只要queue 它的binding key 匹配上 消息的 routing key ,隊列就能收到消息。
多綁定:
多個隊列queue 使用 相同的 binding key。 如果這樣來設計,那麼它的行爲就 類似 fanout。如下圖:
生產日誌/ 發射日誌 (emitting logs)
改進後的日誌系統 使用的 queue 結構如下:
生產者代碼:emit_log_direct.log
<?php
/**
* Author: zhaozhiliang
* Date: 2020/4/21 下午3:46
*/
require_once __DIR__. '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
//創建一個 連接 到 RabbitMq服務器
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
//創建一個channel,大多數 API 都要使用它來做一些事情。
$channel = $connection->channel();
$channel->exchange_declare('direct_logs', 'direct', false,false, false);
$severity = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'info';
$data = implode('', array_slice($argv, 2));
if (empty($data)) {
$data = "info: Hello World!";
}
$msg = new AMQPMessage($data);
$channel->basic_publish($msg, 'direct_logs', $severity);
echo ' [x] Sent ',$severity, ":", $data, "\n";
$channel->close();
$connection->close();
消費者代碼:receive_logs_direct.log
<?php
/**
* Author: zhaozhiliang
* Date: 2020/4/21 下午4:29
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->exchange_declare('direct_logs', 'direct', false, false, false);
list($queue_name, ,) = $channel->queue_declare("", false, false,true, false);
$severities = array_slice($argv, 1);
if (empty($severities)) {
file_put_contents('php://stderr', "Usage: $argv[0] [info] [warning] [error]\n");
exit(1);
}
//對 日誌 各種級別 進行綁定
foreach($severities as $severity) {
$channel->queue_bind($queue_name, 'direct_logs', $severity);
}
echo " [*] Waiting for logs. To exit press CTRL+C\n";
$callback = function ($msg) {
echo ' [x] ', $msg->body, "\n";
};
$channel->basic_consume($queue_name, '', false, true, false, false, $callback);
while ($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();
5 、topics 通配符模式
儘管使用 direct exchange 提高了 我們的系統,它仍然有限制, 它不能 基於多個準則來 路由。
像unix 的 syslog 工具,它 是基於 安全級別( info/warning/critical …) 和 設備來源 (auth/cron/kernel…)
比如 syslog 可以做到 僅 監聽 來自 cron 的errors 信息 和 來自 kern 的所有log信息
我們的log系統 爲了做到 像syslog 那樣,我們需要 topic exchange
routing_key 由 點號連接着的一列單詞 如:quick.orange.rabbit 最大長度 255個字符。
binding keys 有兩個特別重要的情況:
星號* 代替一個單詞
# 號 可以代替 0 或 多個單詞。
routing key 由 3個單詞 組成 speed.colour.species //速度。顏色。物種
我們創建3個 binding key:
Q1 是 用 binding key *.orange.*
Q2 的 binding key *.*.rabbit 和 lazy.#
一個消息 它的 routing key 被設置爲 “quick.orange.rabbit” ,將被投遞給 2個queue
消息“ lazy.orange.elephant ,也將被投遞給2個queue
"quick.orange.fox" 將去到 第一個 queue
lazy.brown.fox 將去到 第二個queue
lazy.pink.rabbit" 將被投遞給 第二個 queue 一次。即便是它 和 2個 binding key 都匹配
"quick.brown.fox" 不匹配任何binding ,所以它將被丟棄。
像 "orange" or "quick.orange.male.rabbit 是 一個單詞或者 四個單詞 ,不匹配任何 binding key ,將被丟棄
"lazy.orange.male.rabbit 儘管它有四個單詞,將匹配 lazy.# 將去到 第二個 queue
注意:當一個 queue 綁定了 “#”,它將接收所有的消息,忽略 routing key ,就像 fanout exchange
當 binding key 中沒有 * 和 #,那麼 topic exchange 的行爲就像 direct exchange
生產者代碼:emit_log_topic.php
<?php
/**
* Author: zhaozhiliang
* Date: 2020/4/21 下午11:14
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$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);
$channel->basic_publish($msg, 'topic_logs', $routing_key);
echo ' [x] Sent ', $routing_key, ':', $data, "\n";
$channel->close();
$connection->close();
消費者代碼:receive_logs_topic.php
<?php
/**
* Author: zhaozhiliang
* Date: 2020/4/21 下午11:21
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$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 ($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();
6、 RPC
如果 我想在 遠端的 計算機上 運行 一個 函數 並等待函數的 返回結果 。 這種模式 通常叫做 RPC
例子 : service 只返回 數字。
Callback queue
消息的屬性:
AMQP 0-9-1 協議預定義了 14個屬性,大多數 很少用,有幾個還是能用到的 如:
delivery_mode //標記消息是否是持久的
content_type //編碼格式,通常使用json編碼,如: application/json
reply_to //通常用來命名 一個 callback queue
correlation_id // 用於 關聯 Rpc response 和 requests
correlation id
如果我們看到一個 unknown 的 correlation_id 值,我們可以安全地刪除 這個消息。
你可能會問,爲什麼我們是忽略 unknown 消息,而不是 發出一個error 錯誤呢。
這是由於 在服務端存在 罕見的情況。
rpc server 發送完answer 後,還沒來得及發送 ack message 給 request,這時候 rpc server 死掉了。
如果這樣的事發生了,重啓rpc server後 將再次處理request。
這就是爲什麼 client 必須能優雅地處理 重複的 響應,並且 RPC server的處理 也應該是冪等性的。
client 代碼:rpc_client.php
<?php
/**
* Author: zhaozhiliang
* Email: [email protected]
* Date: 2020/4/23 下午10:48
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
class FibonacciRpcClient
{
private $connection;
private $channel;
private $callback_queue;
private $response;
private $corr_id;
public function __construct()
{
$this->connection = new AMQPStreamConnection(
'localhost',
5672,
'guest',
'guest'
);
$this->channel = $this->connection->channel();
list($this->callback_queue, ,) = $this->channel->queue_declare(
"",
false,
false,
true,
false
);
$this->channel->basic_consume(
$this->callback_queue,
'',
false,
true,
false,
false,
array(
$this,
'onResponse'
)
);
}
public function onResponse($rep)
{
if($rep->get('correlation_id') == $this->corr_id) {
$this->response = $rep->body;
}
}
public function call($n)
{
$this->response = null;
$this->corr_id = uniqid();
$msg = new AMQPMessage(
(string) $n,
array(
'correlation_id' => $this->corr_id,
'reply_to' => $this->callback_queue
)
);
$this->channel->basic_publish($msg, '', 'rpc_queue');
while(!$this->response) {
$this->channel->wait();
}
return intval($this->response);
}
}
$fibonacci_rpc = new FibonacciRpcClient();
$response = $fibonacci_rpc->call(30);
echo ' [.] Got ', $response, "\n";
server代碼:
<?php
/**
* Author: zhaozhiliang
* Email: [email protected]
* Date: 2020/4/22 下午11:50
*/
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('rpc_queue', false, false, false, false);
function fib($n)
{
if ($n == 0) {
return 0;
}
if ($n == 1) {
return 1;
}
return fib($n-1) + fib($n-2);
}
echo " [x] Awaiting RPC requests\n";
$callback = function($req) {
$n = intval($req->body);
echo '[.] fib(', $n, ")\n";
$msg = new AMQPMessage(
(string) fib($n),
array('correlation_id' => $req->get('correlation_id'))
);
$req->delivery_info['channel']->basic_public(
$msg,
'',
$req->get('reply_to')
);
$req->delivery_info['channel']->basic_ack(
$req->delivery_info['delivery_tag']
);
};
$channel->basic_qos(null, 1, null);
$channel->basic_consume('rpc_queue',
'',
false,
false,
false,
false,
$callback
);
while($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();
如果 RPC server 太慢,你可以僅僅 再運行 另外一個 server就可以了
對於client ,client 需要一個 網絡來回 對於一個 單獨的RPC request.
rabbitmq命令:
sudo rabbitmqctl list_queues
sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
列出 exchanges
sudo rabbitmqctl list_exchanges
列出存在的綁定。
rabbitmqctl list_bindings