RabbitMQ 原理介紹及安裝部署
標簽:RabbitMQ 安裝
簡介
RabbitMQ 是一個用 Erlang 語言開發(fā)的 AMQP 開源實現(xiàn)艰亮。AMQP(Advanced Message Queue Protocol)盅抚,高級消息隊列協(xié)議唆途,是異步消息處理領(lǐng)域的一個公開標準笙僚,主要由 Cisco阿宅、RedHat 等聯(lián)合制定接谨。而 RabbitMQ 就是 AMQP 的一個開源實現(xiàn),由 RabbitMQ Technologies Ltd 公司開發(fā)并提供商業(yè)支持芽唇。
RabbitMQ 主要應用于大型系統(tǒng)中不同的應用或者子系統(tǒng)之間的通信顾画,通過分隔數(shù)據(jù)的發(fā)送和接收來解耦應用。
一條消息的“一生”
在對 RabbitMQ 進行更進一步的介紹之前匆笤,先讓我們來看一看在 RabbitMQ 中研侣,一條消息,從生產(chǎn)者到消費者完整的軌跡炮捧。
當生產(chǎn)者發(fā)布一條消息時庶诡,首先跟 RabbitMQ 建立連接(channel),通過該連接將想要發(fā)布的消息發(fā)送到交換器(exchange)上咆课。交換器通過特定的路由規(guī)則(routing_key)末誓,將消息發(fā)送到某個隊列(queue)。RabbitMQ 會監(jiān)控該隊列书蚪,一旦發(fā)現(xiàn)有消費者訂閱了該隊列喇澡,就將消息發(fā)送給消費者進行處理,然后將該消息從隊列中刪除殊校。
需要注意的是晴玖,這里提到的生產(chǎn)者和消費者只是消息發(fā)送和接收的概念體現(xiàn),每個客戶端都可以是消費者或生產(chǎn)者为流。
接下來呕屎,對上面涉及到的一些重要的概念進行進一步的介紹。
信道
channel敬察,是消費者或生產(chǎn)者與 RabbitMQ 之間的一條連接秀睛,本質(zhì)上是 TCP 連接中的一個虛擬連接。在 RabbitMQ 中静汤,消息的發(fā)送和接收琅催、隊列的訂閱等操作都是通過信道完成的居凶。
之所以選擇信道,而不是在 TCP 連接上進行命令的發(fā)送藤抡,主要是基于性能的考慮侠碧。在操作系統(tǒng)中,建立和銷毀 TCP 連接的開銷是很昂貴的。而且,同一時刻白翻,操作系統(tǒng)對于 TCP 連接的數(shù)量也是有限制的,很容易成為性能的瓶頸替饿。而采用信道就不會有這種問題,可以在一個 TCP 連接中贸典,任意的創(chuàng)建多條信道视卢。
路由鍵
routing_key,是一條特定的規(guī)則廊驼,決定了消息將要被發(fā)送到哪個隊列据过。每條消息在發(fā)布的時候,都需要指定自己的 routing_key妒挎。
RabbitMQ 通過路由鍵實現(xiàn)了隊列和交換器之間的綁定绳锅。
交換器
exchange,生產(chǎn)者將消息發(fā)送給交換器酝掩,然后由交換器根據(jù)路由規(guī)則鳞芙,決定將消息發(fā)送到哪個隊列。
交換器本質(zhì)上只是一個名稱和一個隊列綁定列表期虾,當消息被發(fā)布到交換器時原朝,實際上是所連接的信道將消息上的路由鍵和交換器中的綁定列表做比較,然后路由消息
在 RabbitMQ 中镶苞,常用的交換器類型有三種:direct竿拆、fanout 和 topic。下面宾尚,對這三種類型的交換器做更進一步的介紹。
direct
如果消息中的路由鍵和某個隊列的路由鍵匹配的話谢澈,就將消息發(fā)送給該隊列煌贴。
RabbitMQ 默認實現(xiàn)了一個名稱為空的 direct 交換器,當聲明一個隊列時锥忿,如果沒有指定交換器牛郑,那么 RabbitMQ 會把該隊列自動綁定到這個默認的交換器,并以隊列名稱作為路由鍵敬鬓。
在 RabbitMQ 中淹朋,支持在一個交換器上的多個隊列配置相同的路由鍵笙各。也就是說,對于綁定到交換器 Exchang_A 上的隊列 Queue_1 和 Queue_2础芍,可以設置同一個 routing_key(假設為 key_test)杈抢。當設置了 routing_key 為 key_test 的消息 Message 被發(fā)布到 Exchang_A 上時,Exchang_A 會將 Message 同時發(fā)送給 Queue_1 和 Queue_2 兩個隊列仑性。
fanout
設置為 fanout 的交換器惶楼,會將消息發(fā)送給所有綁定到它身上的隊列,類似于廣播诊杆。
通常應用于需要對一條消息做不同反應的場景中歼捐。比如,在社交網(wǎng)站上晨汹,如果用戶上傳了一張照片豹储,在更新用戶相冊的同時,還需要給用戶一些積分獎勵淘这。那么這種情況剥扣,就可以使用 fanout 類型的交換器來實現(xiàn)。只需要將更新用戶相冊的隊列和增加用戶積分的隊列綁定到同一個 fanout 交換器上即可慨灭。
topic
topic 類型的交換器朦乏,可以使來自不同源頭的消息到達同一個隊列,即支持在路由鍵中使用通配符氧骤。
在 RabbitMQ 中呻疹,.
把路由鍵分成多個部分,*
匹配特定位置的任意文本筹陵,#
則表示匹配所有規(guī)則刽锤。通過對這幾種通配符的組合使用,就可以實現(xiàn)將不同來源的消息發(fā)送到同一個隊列朦佩。比如并思,將 routing_key 設置為 *.error
,就可以將所有 routing_key 以 .error
結(jié)尾的消息發(fā)送到同一個隊列语稠。
隊列
queue宋彼,生產(chǎn)者發(fā)布的消息最終到達的地方,同時消費者從隊列中消費消息仙畦。
接收消息
消費者主要通過兩種方式從隊列中接收消息:使用 basic.consume 和 basic.get 命令输涕。
當消費者使用 basic.consume 訂閱了某個隊列后,一旦有消息到達該隊列慨畸,RabbitMQ 就將消息立即發(fā)送給消費者莱坎,然后等待下一條消息的到來。
如果消費者使用的是 basic.get 命令寸士,只會從隊列中獲取單條消息檐什,無法持續(xù)獲取碴卧。假如隊列中堆積了 5 條消息,使用 basic.get 命令只會獲得最開始的那條消息乃正,后面的 4 條消息無法獲取住册。
如果一個隊列有多個消費者進行訂閱,RabbitMQ 采用輪詢的方式將消息發(fā)送給某個消費者烫葬,每條消息只發(fā)送給一個消費者界弧。
也就是說,如果消費者 A搭综、B垢箕、C訂閱了同一個隊列,那么第一條消息會發(fā)送給 A兑巾,第二條發(fā)送給 B条获,第三條發(fā)送給 C,第四條發(fā)送給 A蒋歌,···帅掘,以此類推。
當消息被消費者消費了之后堂油,RabbitMQ 就將該消息從隊列中刪除修档。
那么 RabbitMQ 怎么知道消息被消費者成功消費了呢?這就涉及到了消息的確認機制府框。
消息確認
消費者接收到的每條消息都必須進行確認吱窝,如果消費者沒有對消息進行確認,那么 RabbitMQ 不會將下一條消息發(fā)送給該消費者迫靖,直到其對消息進行了確認院峡。如果在消費者向 RabbitMQ 發(fā)送確認之前,消費者與 RabbitMQ 之間的連接斷開了系宜,那么 RabbitMQ 會將該消息發(fā)送給其他的消費者照激。
主要有兩種確認方式:使用 basic.ack 命令向 RabbitMQ 發(fā)送確認,或者在訂閱隊列時將 auto_ack 參數(shù)設置為 true盹牧。
需要注意的是俩垃,如果設置了 auto_ack 為 true,那么一旦消費者接收到了消息汰寓,RabbitMQ 就認為確認了消息吆寨,從而將消息從隊列中刪除。但是消費者接收到消息并不等同于成功處理了消息踩寇,如果在成功處理該條消息之前出現(xiàn)問題或者程序崩潰,由于此時 RabbitMQ 已經(jīng)將消息從隊列中刪除了六水,那么就意味著這條消息丟失了俺孙。
虛擬主機
vhost辣卒,簡化版的 RabbitMQ 服務器,每一個 vhost 擁有自己的交換器睛榄、隊列和綁定荣茫。更重要的是,它擁有自己的權(quán)限场靴,不同的 vhost 之間是隔離的啡莉。可以將 vhost 想象成物理服務器上的虛擬機旨剥。
RabbitMQ 中默認的虛擬主機為:“/”咧欣。
消息持久化
默認情況下,如果 RabbitMQ 進行了重啟轨帜,那么隊列魄咕、交換器和其中的消息都會丟失。如果想要你的數(shù)據(jù)在重啟后不丟失蚌父,那么就需要對消息進行持久化設置哮兰。主要操作如下:
將消息的投遞模式(delivery mode)設置為 2(持久)。
將消息發(fā)送到持久化的交換器苟弛。
消息必須到達持久化的隊列喝滞。
RabbitMQ 是通過將消息寫入磁盤中的持久化日志中的方式實現(xiàn)消息的持久化的。如果持久化隊列中的某條消息被消費了膏秫,那么 RabbitMQ 會在持久化日志中將該消息標記為等待垃圾收集右遭。
管理 RabbitMQ
前面的部分介紹了一些 RabbitMQ 中比較重要的概念和消息的相關(guān)知識,接下來介紹如何對 RabbitMQ 進行管理荔睹。
首先需要明確一個概念狸演,通常提到的 RabbitMQ 節(jié)點,實際上指的是 RabbitMQ 應用和所在的 Erlang 節(jié)點僻他。RabbitMQ 是 Erlang 應用程序的一種宵距。
啟動 RabbitMQ 通常使用 rabbitmq-server
工具,但需要注意的是吨拗,使用該命令啟動的包括 Erlang 節(jié)點和 RabbitMQ 應用满哪。同時,還把 RabbitMQ 應用設置成了獨立運行模式劝篷。
對于 RabbitMQ 應用的管理哨鸭,通常使用 rabbitmqctl
工具:
stop 參數(shù):將本地節(jié)點干凈的關(guān)閉,包括 RabbitMQ 應用和 Erlang 節(jié)點娇妓。同時像鸡,可以使用
-n rabbit@hostname
參數(shù),關(guān)閉指定的遠程節(jié)點哈恰。stop_app 參數(shù):只關(guān)閉 RabbitMQ 應用只估。
start_app 參數(shù):只啟動 RabbitMQ 應用志群。
集群
對于 RabbitMQ 的內(nèi)建集群,主要用于完成兩個設計目標:
- 允許消費者和生產(chǎn)者在節(jié)點崩潰的情況下繼續(xù)運行蛔钙。
- 通過添加更多的節(jié)點來線性擴展消息通信吞吐量锌云。
在默認情況下,如果集群中某個節(jié)點崩潰了吁脱,那么在該節(jié)點上隊列上的消息也就丟失了桑涎,因為 RabbitMQ 不會將節(jié)點上的隊列復制到整個集群中。
不論是在單節(jié)點系統(tǒng)中還是集群兼贡,對于 RabbitMQ 節(jié)點來說攻冷,要么是內(nèi)存節(jié)點,要么是磁盤節(jié)點紧显。兩者間的主要區(qū)別:
內(nèi)存節(jié)點:所有隊列讲衫、交換器、綁定孵班、用戶涉兽、權(quán)限和 vhost 的元數(shù)據(jù)定義都只是存儲在內(nèi)存中。
磁盤節(jié)點:所有的元數(shù)據(jù)信息存儲在磁盤中篙程。對于單節(jié)點系統(tǒng)枷畏,只允許節(jié)點為磁盤節(jié)點。
當在集群中聲明交換器虱饿、隊列和綁定時拥诡,這些操作會等到集群中所有節(jié)點都成功提交元數(shù)據(jù)后才返回。
在 RabbitMQ 集群中氮发,要求至少有一個磁盤節(jié)點渴肉,當有節(jié)點加入或離開時,需要將該變更通知到至少一個磁盤節(jié)點爽冕。
安裝
分別介紹單節(jié)點和集群的安裝部署仇祭。
單節(jié)點
依賴
RabbitMQ 是使用 Erlang 編寫的,因此需要安裝 Erlang 庫颈畸,以便運行 RabbitMQ乌奇。
安裝 Erlang
下載 Erlang 源碼
點擊 這里 下載 Erlang 源碼包,并解壓至指定目錄眯娱。
配置 ERL_TOP
export ERL_TOP=`pwd`
編譯
使用以下命令進行編譯:
./configure --prefix=/path/to/install/erlang
make
make install
設置環(huán)境變量
編譯完成后礁苗,設置 ERL_HOME。編輯 /etc/profile 文件徙缴,增加以下內(nèi)容:
export ERL_HOME=/path/to/install/erlang
export PATH=$PATH:$ERL_HOME/bin
驗證
執(zhí)行命令:erl
试伙,可以進入 Erlang 環(huán)境,證明安裝成功。
下載 RabbitMQ
點擊 這里 下載 RabbitMQ Server 安裝包迁霎,并解壓至指定目錄(如:/path/to/install/rabbitmq-server
)吱抚。
設置文件夾結(jié)構(gòu)
創(chuàng)建兩個目錄:RabbitMQ 的日志目錄和 Mnesia 數(shù)據(jù)庫目錄。RabbitMQ 使用 Mnesia 數(shù)據(jù)庫存儲服務器信息考廉,比如隊列元數(shù)據(jù)、虛擬主機等携御。
mkdir -p /var/log/rabbitmq
mkdir -p /var/lib/rabbitmq/mnesia/rabbit
啟動
執(zhí)行命令:/path/to/install/rabbitmq-server/sbin/rabbitmq-server
啟動 RabbitMQ Server昌粤。
出現(xiàn)以下提示信息,說明啟動成功:
Activating RabbitMQ plugins ...
********************************************************************************
*WARNING* Undefined function global:safe_whereis_name/1
********************************************************************************
0 plugins activated:
+---+ +---+
| | | |
| | | |
| | | |
| +---+ +-------+
| |
| RabbitMQ +---+ |
| | | |
| v2.7.0 +---+ |
| |
+-------------------+
AMQP 0-9-1 / 0-9 / 0-8
Copyright (C) 2007-2011 VMware, Inc.
Licensed under the MPL. See http://www.rabbitmq.com/
node : rabbit@172-23-8-23
app descriptor : /home/xuzhidan/bigdata/RabbitMQ/rabbitmq_server-2.7.0/sbin/../ebin/rabbit.app
home dir : /root
config file(s) : (none)
cookie hash : TJy1BzDGsu3ovCCTHWG7rw==
log : /var/log/rabbitmq/rabbit@172-23-8-23.log
sasl log : /var/log/rabbitmq/rabbit@172-23-8-23-sasl.log
database dir : /var/lib/rabbitmq/mnesia/rabbit@172-23-8-23
erlang version : 8.3
-- rabbit boot start
starting file handle cache server ...done
starting worker pool ...done
starting database ...done
starting codec correctness check ...done
-- external infrastructure ready
starting plugin registry ...done
starting auth mechanism cr-demo ...done
starting statistics event manager ...done
starting logging server ...done
starting auth mechanism amqplain ...done
starting auth mechanism plain ...done
starting exchange type direct ...done
starting exchange type fanout ...done
starting exchange type headers ...done
starting exchange type topic ...done
-- kernel ready
starting node monitor ...done
starting cluster delegate ...done
starting guid generator ...done
starting alarm handler ...done
starting memory monitor ...done
-- core initialized
starting empty DB check ...done
starting exchange, queue and binding recovery ...done
starting mirror queue slave sup ...done
starting adding mirrors to queues ...done
-- message delivery logic ready
starting error log relay ...done
starting networking ...done
starting direct_client ...done
starting notify cluster nodes ...done
broker running
集群
需要在集群中的所有節(jié)點上安裝 RabbitMQ啄刹,具體安裝步驟參照上面單節(jié)點的安裝過程涮坐。
同步 cookie 文件
RabbitMQ 集群是通過 Erlang 的集群實現(xiàn)的,當集群中的節(jié)點進行通信時誓军,Erlang 節(jié)點會進行認證袱讹。如果節(jié)點之間的 Erlang cookie 不相同,則會認證失敗昵时。因此捷雕,需要在集群中的所有節(jié)點上同步 cookie 文件。
拷貝 cookie
如果是通過上面介紹的單節(jié)點的方式安裝的 RabbitMQ壹甥,則 Erlang 的 cookie 文件路徑為:/root/.erlang.cookie
救巷。
將集群中任意一個節(jié)點上的 cookie 文件拷貝到其他的節(jié)點上,進行替換句柠。
修改權(quán)限
RabbitMQ 在啟動每個節(jié)點時浦译,會檢查節(jié)點上的 cookie 文件的權(quán)限,必須為 400溯职,否則會報錯精盅。因此需要將每個節(jié)點上的 cookie 文件的權(quán)限修改為 400 。
配置主機名
設置主機名
RabbitMQ 是通過主機名來對節(jié)點進行管理的谜酒,因此需要對集群中的每個節(jié)點都設置一個唯一的主機名叹俏。
可通過修改配置文件 /etc/sysconfig/network
永久修改主機名。
添加 IP 主機名映射
修改節(jié)點上的 /etc/hosts
文件甚带,添加集群中所有節(jié)點的IP和主機名映射她肯,并在集群中同步。
啟動集群
假設集群中有三個節(jié)點:host1鹰贵、host2和host3晴氨,通過以下步驟將整個集群啟動。
啟動服務
在 host1 上執(zhí)行以下命令碉输,啟動服務:
cd /path/to/install/rabbitmq-server
sh sbin/rabbitmq-server -detached
在 host2 和 host3 上執(zhí)行以下命令籽前,啟動服務,并重置 RabbitMQ 應用:
cd /path/to/install/rabbitmq-server
sh sbin/rabbitmq-server -detached
sh sbin/rabbitmqctl stop_app
sh sbin/rabbitmqctl reset
加入集群
在 host2 和 host3 上分別執(zhí)行以下命令,加入到集群中
cd /path/to/install/rabbitmq-server
sh sbin/rabbitmqctl cluster rabbit@host1 rabbit@host2
其中枝哄,host1 和 host2 作為集群中的磁盤節(jié)點肄梨,host3 作為集群中的內(nèi)存節(jié)點。
啟動 RabbitMQ 應用
在 host2 和 host 3 上分別執(zhí)行以下命令挠锥,啟動 RabbitMQ 應用程序:
cd /path/to/install/rabbitmq-server
sh sbin/rabbitmqctl start_app
查看狀態(tài)
執(zhí)行以下命令众羡,查看集群的狀態(tài):
cd /path/to/install/rabbitmq-server
sh sbin/rabbitmqctl cluster_status
顯示以下信息,說明集群部署成功:
[root@172-23-8-24 rabbitmq_server-2.7.0]# sbin/rabbitmqctl cluster_status
Cluster status of node 'rabbit@172-23-8-24' ...
[{nodes,[{disc,['rabbit@172-23-8-24','rabbit@172-23-8-23']}]},
{running_nodes,['rabbit@172-23-8-23','rabbit@172-23-8-24']}]
...done.