要列出可用插(步驟1),我們將得到下面的屏幕輸出:
上圖顯示的是所有可用的插件,其中方括號中為空的表示還未安裝. 標記為[E]的插件是明確安裝的. 標記為[e]的插件是隱式安裝的,也就是說,這些插件是作為其它的插件的依賴而進行安裝的.
在安裝了STOMP插件之后,我們必須重啟broker以讓修改生效.
一旦插件激活了,你可以使用簡單的文本STOMP協議來向隊列test發送消息(步驟4). 這樣你將看到下面的截圖:

在另一個終端,我們可以啟動隊列test來消費消息(步驟5). 這樣你將看到下面的截圖:

請注意,從消息到最后的文本沒有被類型化,這是實際接收到的消息。
更多在這個食譜中,我們使用了標準的STOMP配置。然而,也可以通過RabbitMQ配置文件的選項來定制其端口,SSL使用.
你可在http://www.rabbitmq.com/stomp.html查找到更多詳細信息.
TIP
注意STOMP完全不同于Web-Stomp, Web-Stomp是封裝在WebSockets中的STOMP.參考第5章節在web應用程序中使用STOMP來開發web監控程序食譜的內容.這兩種協議不具有互操作性。
此外,也可以使用STOMP來發送其它類型的消息。如使用臨時隊列來發送RPC消息,向交換器發送消息,或從交換器中接收消息.
也可參考
在本食譜中,我們已經展示了如何使用Netcat作為文本客戶端來讓RabbitMQ與STOMP插件交互. 但,這不是一種典型在客戶端使用STOMP的方式.
這里有許多可用的STOMP客戶端APIs.
你可在http://stomp.github.io/implementations.html中找到可用客戶端包的列表.
管理RabbitMQ集群
當部署了一個大的RabbitMQ集群時,管理插件會對集群操作造成一定的開銷.在本食譜中,我們將展示如何減輕這種開銷。
準備
為了驗證這個食譜,你需要一個具有至少兩個節點的RabbitMQ集群。如果他們已經安裝了管理插件,你需要刪除它。
如何做1. 使用下面的命令在一個節點上安裝管理插件:
rabbitmq-plugins enable rabbitmq_management
2.使用以下命令在所有其他節點上安裝管理代理插件:
rabbitmq-plugins enable rabbitmq_management_agent
如何工作
執行這些步驟后,您只能從第一個節點監視整個群集。其他節點將通過代理來更新第一個節點的控制臺狀態,但您無法訪問他們的端口15672。
通常,你會在幾個節點安裝完整的管理插件,如前端或管理節點和管理代理插件的其它節點。
監控Shovel狀態
在第7章節,開發高可用應用程序中,我們已經看過了如何使用Shovel插件.在本食譜中,我們將展示如何使用一個適當的插件來監控其正確行為. 這是rabbitmq_management插件的擴展.
準備
要測試這個食譜,我們需要運行兩個RabbitMQ brokers. 在本食譜中,我們將其稱為rabbit@node01和rabbit@node02.
如何做
我們假設這兩個broker已經在他們各自的節點上運行了.我們將使用配置文件來配置節點node01上的broker,你也可以從Chapter07/Recipe05中拷貝配置文件:
1. 在RabbitMQ配置文件中,一般是/etc/rabbit/rabbitmq.config,插入下面的Shovel配置:
[{rabbitmq_shovel,
[ {shovels, [ {my_books_shovel,
[
{sources, [ {broker, "amqp://node02"}]}
, {destinations, [ {broker, "amqp://"}]}
, {queue, <<"myBooksQueueCopy">>}
, {prefetch_count, 10}
, {reconnect_delay, 5}
]}]}].
2. 輸入下面的命令來激活插件:
rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins enable rabbitmq_shovel
rabbitmq-plugins enable rabbitmq_shovel_management
3. 為修改的broker重啟broker以使配置生效,命令如下:
service rabbitmq-server restart
4. 使用下面的地址來訪問RabbitMQ 管理界面:
http://node01:15672/
5. 從管理界面中,分別在節點node01和node02上創建myBooksQueueCopy隊列.
6. 在管理界面,導航至Admin | Shovel Status.
如何工作
當我們激活Shovel插件時,可通過rabbitmq_shovel_management 插件來監控其行為. 一旦我們激活了插件,由于重定向隊列不存在,你會看到錯誤信息。顯示如下:
只要我們創建了隊列(步驟5),頁面將在5秒內自動刷新:

在這個頁面上, RabbitMQ 允許我們監視所有已配置的Shovels.
開發新插件 – 使用ODBC來操作關系型數據庫
在前面的食譜中,我們已經看過了,如何使用一些現有的插件?,F在,我們將了解如何來開發自定義新插件.
注意,這不是一種典型實踐. 大部分的操作通??赏ㄟ^ RabbitMQ/AMQP client API來執行.
然而,在某些必要的情況下,也需要執行一些定制化的操作.
這是出于優化目的,或需要嚴格監控broker自己的行為.
在本食譜中,我們將展示如何讓RabbitMQ來消費消息,并使用ODBC驅動將其存入關系型數據庫中.準備
在這個食譜中,我們需要RabbitMQ 和PostgreSQL. 然而, 由于ODBC驅動的普及,本食譜可以很容易地適應到幾乎所有關系數據庫上。
另外,我們還需要安裝Mercurial (http://mercurial.selenic.com/),它是RabbitMQ的版本系統,用來檢出RabbitMQ的源代碼.
雖然這里的環境是Linux,但只需要稍為修改,本食譜也能工作在Windows上.
如何做
現在,我們將安裝和配置PostgreSQL.
1. 安裝PostgreSQL和它的ODBC驅動. 例如,在基于yum的Linux發行版上(如RedHat, CentOS, Fedor或其它),用roo執行下面的命令.
yum install postgresql-server
yum install postgresql-odbc
postgresql-setup initdb
service postgresql start
2. 從RabbitMQ插件中,使用下面的命令來創建一個新用戶(密碼為rmq_plugin_password) 和一個新數據庫:
su postgres createuser --no-superuser --no-createdb --no-createrole --pwpromptrmq_plugin_user
createdb --owner rmq_plugin_userrmqdb
3. ,通過在文件/var/lib/pgsql/data/pg_hba.conf末尾追加下面的行,以允許新創建的用戶訪問給定數據庫(只允許從本地訪問):
# TYPE DATABASE USER ADDRESS METHOD
local rmqdb rmq_plugin_user md5
host rmqdb rmq_plugin_user 127.0.0.1/32 md5
4.以root身份重新加載PostgreSQL配置:
service postgresql reload
5. 此時,你應該可以從本地連接PostgreSQL了,例如,通過執行下面的命令:
psql --username=rmq_plugin_user --dbname=rmqdb
6. 完成ODBC驅動的配置來訪問數據庫,要做到這一點,必須在文件/etc/odbc.ini中插入下面的行:
[rmqDSN]
Driver = PostgreSQL
Description = PostgreSQL data source for RabbitMQ
Servername = localhost
Port = 5432
Protocol = 8.4
Database = rmqdb
7.現在我們可以使用isql命令來測試ODBC連接,同時我們也可以直接使用Erlang來測試. erl命令如下:
odbc:start()
odbc:connect("DSN=rmqDSN;UID=rmq_plugin_user;PWD=rmq_plugin_password", [])
到目前為止,我們已經準備好了開發插件所需要的東西.現在我們來了解如何啟用metronome 插件.它存在于官方RabbitMQ文檔(http://www.rabbitmq.com/plugin-development.html:
8. 使用下面的命令來檢出RabbitMQ開發源代碼樹:
cd $HOME
hg clone http://hg.rabbitmq.com/rabbitmq-public-umbrella
cd rabbitmq-public-umbrella
make co
9. 使用下面的命令來編譯metronome插件:
cd rabbitmq-metronome
make
10. 在開發的broker中安裝插件及其依賴.
cd ../rabbitmq-server
mkdir plugins
cd plugins
ln –s ../../rabbitmq-metronome
ln–s../../rabbitmq-erlang-client
11.為了避免覆蓋產品環境安裝,即使是我們不用root用戶,我們也需要停止產品服務器,設置一些環境變量,并創建一些相應的目錄以讓RabbitMQ以標準用戶啟動:
export RABBITMQ_LOG_BASE=$HOME/rmq/log
export RABBITMQ_MNESIA_BASE=$HOME/rmq/mnesia
export RABBITMQ_ENABLED_PLUGINS_FILE=$HOME/rmq/enabled_plugins
mkdir –p $RABBITMQ_LOG_BASE $RABBITMQ_MNESIA_BASE
12. 現在我們可以啟用開發插件了.
cd $HOME/rabbitmq-public-umbrella/rabbitmq-server
scripts/rabbitmq-plugins list
scripts/rabbitmq-plugins enable rabbitmq_metronome
13. 最后,啟動開發服務器:
scripts/rabbitmq-server
14. 此刻,我們已經準備好了如何開發一個新插件, 它使得通過ODBC的方式,將RabbitMQ與第三方數據庫連接到了一起.你可在Chapter09/Recipe04中找到本食譜的源碼. 你可從Chapter09/Recipe04/
rabbitmq-odbctap目錄拷貝源碼進RabbitMQ開發樹-rabbitmq-publicumbrella(在步驟8中檢出來的). 通過這種方式,你可以獲得類似于下面截圖的源碼樹: 
15. 要開始開發一個新插件,需要從現有插件rabbitmq-metronome 或 rabbitmq-shovel中拷貝和重命名文件. The makefile will be left unmodified.
16. 修改package.mk文件以反映所需的依賴與測試模塊.
17. 編輯rabbitmq_odbctap.app.src. 此文件包含Erlang項目所需的資源,在我們的例子中,一般和慣例都必須包含下面的配置:
{application, rabbitmq_odbctap,
[{description, "Embedded Rabbit ODBC tap"},
{vsn, "0.0.0"},
{modules, []},
{registered, []},
{mod, {rabbit_odbctap, []}},
{env, [{dsn,"DSN"},
{user,"guest"},
{password, "guest"},
{queue, "tapped_queue"}
]},
{applications, [kernel, stdlib, rabbit, amqp_client]}]}.
18. 定制rabbit_odbctap.erl, 模塊的入口點,為了讓它啟動或停止,需要配置插件自身.
19. 定制rabbit_odbctap_sup.erl, 對于Erlang管理源節點,通過定義回調來定義主管行為的回調.
20. 在rabbit_odbctap_worker.erl中實現插件邏輯.這是實際模塊的入口點,在我們這里,它會連接RabbitMQ broker,綁定隊列,并通過ODBC來消費指定數據庫包含的消息.
21.多個模塊共用的數據定義(也就是Erlang記錄)可放置在include目錄中.如,在rabbit_odbctap.hrl中,你可以找到Erlang記錄odbctap_config的定義,此定義是被rabbit_odbctap.erl、 rabbit_odbctap_worker.erl所共用的.
22. 準備一個或多個測試模塊.在我們的例子中,在rabbit_odbctap_tests.erl中只能找到一個骨架.
23. 編譯插件并執行自動化測試.
cd $HOME/rabbitmq-public-umbrella/rabbimq-odbctap
make
make test
24. 在開發服務器中安裝插件.
cd ../rabbitmq-server/plugins
ln –s ../../rabbitmq-odbctap .
25. 在設置步驟11中所示的環境后,我們可以啟用插件和(重新)啟動服務器了.
cd $HOME/rabbitmq-public-umbrella/rabbitmq-server
scripts/rabbitmq-plugins enable rabbitmq_odbctap
scripts/rabbitmq-server
如何工作
為了實戰本食譜,我們一開始就配置了一個PostgreSQL數據庫,以及它相應的ODBC驅動.這部分內容已經在食譜的前半部分中展示過了.
然后,我們展示了如何啟用樣例模板插件rabbitmq_metronome(RabbitMQ自身在開發樹中提供的).如果一切正常, 步驟13啟動的開發broker將以會以我們標準用戶運行,并在日志文件$HOME/rmq/log/rabbit@localhost.log中,你可能會看到下面的行:
=INFO REPORT==== 21-Oct-2013::03:28:50 ===
Server startup complete; 2 plugins started.
* amqp_client
* rabbitmq_metronome
這是開發新插件的起點,即使用Erlang ODBC client來監控已配置PostgreSQL數據庫中的某些給定隊列.這部分內容將在食譜的第三部分展示。
要實現我們的插件,我們選擇遵循一種公共的方案,即使用模塊來實現Erlang行為.實際上, Erlang 鼓勵使用通過supervisor來解藕應用程序(這里是我們新開發的插件)和運行者(即RabbitMQ自身) 的松耦合架構。
關于這方面的內容,可參考http://www.erlang.org/doc/man/supervisor.html and http://www.erlang.org/doc/design_principles/sup_princ.html.
supervisor唯一需要定制的是,可從startup模塊中獲取配置信息,并將其傳遞給worker模塊. 為了達到目的,startup 模塊(rabbit_odbctap.erl)包含了讀取配置信息的代碼。
read_config() ->
{ok, Dsn} = application:get_env(dsn),
{ok, User} = application:get_env(user),
{ok, Password} = application:get_env(password),
{ok, Queue} = application:get_env(queue),
Config = #odbctap_config{
dsn = Dsn,
user = User,
password = Password,
queue = Queue},
Config.
調用application:get_env/1可讓模塊自動訪問如下設置的定義:
1.在Erlang資源文件rabbitmq_odbctap.app.src中,在編譯時,設置了env鍵:
...
{env, [{dsn,"DSN"},
{user,"guest"},
{password, "guest"},
{queue, "tapped_queue"}
]},
...
在rabbitmq.config文件中是以運行時讀取的,其配置遵循典型的RabbitMQ (即Erlang)格式 , 且在下面的代碼中指定了rabbitmq_odbctap鍵:
[{rabbitmq_odbctap,
[{dsn, "rmqDSN"},
{user,"rmq_plugin_user"},
{password, "rmq_plugin_password"},
{queue, "tapped_queue"}]}].
在本書的歸檔目錄中,你能找到完整的文件.
rabbit_odbctap_worker.erl worker 模塊實現gen_server行為.
你可在http://www.erlang.org/doc/design_principles/gen_server_concepts.html找到更多詳細信息.
在我們的模塊中,一旦模塊啟動了就會調用 init/2,然后它會通過ODBC客戶端 Erlang API http://www.erlang.org/
doc/apps/odbc/來連接ODBC連接器,并觸發RabbitMQ消費者. 重要的一點是,在這種情況下,內嵌RabbitMQ client是連接到本地broker的,即嵌入到同一個Erlang虛擬機中,并會執行下面的調用:
{ok, Connection} = amqp_connection:start(#amqp_params_direct{})
通過這種方式,插件可使用內部Erlang連接和更為高效的消息協議, 因為完全避免了AMQP通信協議的編組.
TIP
為了能在RabbitMQ日志文件中記錄一些信息,你可以使用與rabbit_log:info/2相似的調用,正如init/2中定義的一樣.
通過使用gen_server行為, broker 的消息不是從接收塊中消費的(http://www.rabbitmq.com/erlang-client-user-guide.html, 參考訂閱隊列章節), 而是通過handle_info/2回調實施的:
handle_info({#'basic.deliver'{delivery_tag = Tag},
#amqp_msg{payload = Payload}},State = #state{channel=Channel,odbcHandle = Ohandle}) ->
Query = "INSERT INTO rmqmessages VALUES ('now','"++binary_to_list(Payload) ++"')",
{updated, _} = odbc:sql_query(Ohandle, Query),
amqp_channel:cast(Channel, #'basic.ack'{delivery_tag = Tag}),
{noreply, State};
這是本食譜的核心.當RabbitMQ自身初始化的時候,且數據庫處于打開狀態時,每個消費消息都將得到存儲。
更多
非常重要的一點是開發插件是最后的選擇,最好是通過使用AMQP client library來開發一個外部應用程序.
TIP
一個插件可能連累RabbitMQ的穩定性.
因此,只有當極端的整合或對性能有需要時,才可以評估是否開發一個插件。