問題一:RabbitMQ中的 broker 是指什么?cluster 又是指什么?
答:broker是指一個或多個 erlang node 的邏輯分組,且 node 上運行著 RabbitMQ 應(yīng)用程序。cluster 是在 broker 的基礎(chǔ)之上,增加了 node 之間共享元數(shù)據(jù)的約束。
?
問題二:什么是元數(shù)據(jù)?元數(shù)據(jù)分為哪些類型?包括哪些內(nèi)容?與cluster相關(guān)的元數(shù)據(jù)有哪些?元數(shù)據(jù)是如何保存的?元數(shù)據(jù)在 cluster 中是如何分布的?
答:在非cluster模式下,元數(shù)據(jù)主要分為 Queue 元數(shù)據(jù)(queue 名字和屬性等)、Exchange 元數(shù)據(jù)(exchange 名字、類型和屬性等)、Binding 元數(shù)據(jù)(存放路由關(guān)系的查找表)、Vhost 元數(shù)據(jù)(vhost 范圍內(nèi)針對前三者的名字空間約束和安全屬性設(shè)置)。在cluster 模式下,還包括 cluster 中 node 位置信息和 node 關(guān)系信息。元數(shù)據(jù)按照 erlangnode 的類型確定是僅保存于 RAM 中,還是同時保存在 RAM 和 disk 上。元數(shù)據(jù)在cluster 中是全 node 分布的。
?
問題三:RAM node和 disk node 的區(qū)別?
答:RAM node僅將 fabric(即 queue、exchange 和 binding 等 RabbitMQ 基礎(chǔ)構(gòu)件)相關(guān)元數(shù)據(jù)保存到內(nèi)存中,但 disk node 會在內(nèi)存和磁盤中均進行存儲。RAM node 上唯一會存儲到磁盤上的元數(shù)據(jù)是 cluster 中使用的 disk node 的地址。要求在 RabbitMQ cluster中至少存在一個 disk node 。
?
問題四:RabbitMQ上的一個 queue 中存放的 message 是否有數(shù)量限制?
答:可以認為是無限制,因為限制取決于機器的內(nèi)存,但是消息過多會導(dǎo)致處理效率的下降。
?
問題五:RabbitMQ概念里的 channel、exchange 和 queue 這些東東是邏輯概念,還是對應(yīng)著進程實體?這些東東分別起什么作用?
答:queue具有自己的 erlang 進程;exchange 內(nèi)部實現(xiàn)為保存 binding 關(guān)系的查找表;channel 是實際進行路由工作的實體,即負責(zé)按照 routing_key 將 message 投遞給queue 。由 AMQP 協(xié)議描述可知,channel 是真實 TCP 連接之上的虛擬連接,所有AMQP 命令都是通過 channel 發(fā)送的,且每一個 channel 有唯一的 ID。一個 channel 只能被單獨一個操作系統(tǒng)線程使用,故投遞到特定 channel 上的 message 是有順序的。但一個操作系統(tǒng)線程上允許使用多個 channel 。channel 號為 0 的 channel 用于處理所有對于當前 connection 全局有效的幀,而 1-65535 號 channel 用于處理和特定 channel 相關(guān)的幀。AMQP 協(xié)議給出的 channel 復(fù)用模型如下其中每一個 channel 運行在一個獨立的線程上,多線程共享同一個 socket。
?
問題六:vhost是什么?起什么作用?
答:vhost可以理解為虛擬 broker ,即 mini-RabbitMQ server。其內(nèi)部均含有獨立的queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的權(quán)限系統(tǒng),可以做到vhost 范圍的用戶控制。當然,從 RabbitMQ 的全局角度,vhost 可以作為不同權(quán)限隔離的手段(一個典型的例子就是不同的應(yīng)用可以跑在不同的 vhost 中)。【cluster 相關(guān)】
?
?
問題七:在單node系統(tǒng)和多 node 構(gòu)成的 cluster 系統(tǒng)中聲明 queue、exchange ,以及進行 binding 會有什么不同?答:當你在單 node 上聲明 queue 時,只要該 node 上相關(guān)元數(shù)據(jù)進行了變更,你就會得到 Queue.Declare-ok 回應(yīng);而在 cluster 上聲明 queue ,則要求 cluster 上的全部node 都要進行元數(shù)據(jù)成功更新,才會得到 Queue.Declare-ok 回應(yīng)。另外,若 node 類型為 RAM node 則變更的數(shù)據(jù)僅保存在內(nèi)存中,若類型為 disk node 則還要變更保存在磁盤上的數(shù)據(jù)。
?
?
?
?
問題八:客戶端連接到cluster中的任意 node 上是否都能正常工作?
答:是的??蛻舳烁杏X不到有何不同。
?
問題九:若cluster中擁有某個 queue 的 owner node 失效了,且該 queue 被聲明具有durable 屬性,是否能夠成功從其他 node 上重新聲明該 queue ?
答:不能,在這種情況下,將得到404 NOT_FOUND錯誤。只能等 queue 所屬的 node恢復(fù)后才能使用該 queue 。但若該 queue 本身不具有 durable 屬性,則可在其他 node上重新聲明。
?
問題十:cluster中 node 的失效會對 consumer 產(chǎn)生什么影響?若是在 cluster 中創(chuàng)建了mirrored queue ,這時 node 失效會對 consumer 產(chǎn)生什么影響?
答:若是consumer所連接的那個 node 失效(無論該 node 是否為 consumer 所訂閱queue 的 owner node),則 consumer 會在發(fā)現(xiàn) TCP 連接斷開時,按標準行為執(zhí)行重連邏輯,并根據(jù)“Assume Nothing”原則重建相應(yīng)的 fabric 即可。若是失效的 node 為consumer 訂閱 queue 的 owner node,則 consumer 只能通過 Consumer CancellationNotification 機制來檢測與該 queue 訂閱關(guān)系的終止,否則會出現(xiàn)傻等卻沒有任何消息來到的問題。
?
問題十一:能夠在地理上分開的不同數(shù)據(jù)中心使用RabbitMQ cluster么?
答:不能。第一,你無法控制所創(chuàng)建的queue實際分布在 cluster 里的哪個 node 上(一般使用 HAProxy + cluster 模型時都是這樣),這可能會導(dǎo)致各種跨地域訪問時的常見問題;第二,Erlang 的 OTP 通信框架對延遲的容忍度有限,這可能會觸發(fā)各種超時,導(dǎo)致業(yè)務(wù)疲于處理;第三,在廣域網(wǎng)上的連接失效問題將導(dǎo)致經(jīng)典的“腦裂”問題,而RabbitMQ 目前無法處理(該問題主要是說 Mnesia)?!揪C合問題】
?
問題十二:為什么heavy RPC的使用場景下不建議采用 disk node ?
答:heavy RPC是指在業(yè)務(wù)邏輯中高頻調(diào)用 RabbitMQ 提供的 RPC 機制,導(dǎo)致不斷創(chuàng)建、銷毀 reply queue ,進而造成 disk node 的性能問題(因為會針對元數(shù)據(jù)不斷寫盤)。所以在使用 RPC 機制時需要考慮自身的業(yè)務(wù)場景。問題十三:向不存在的 exchange 發(fā) publish 消息會發(fā)生什么?向不存在的 queue 執(zhí)行consume 動作會發(fā)生什么?答:都會收到 Channel.Close 信令告之不存在(內(nèi)含原因 404 NOT_FOUND)。
?
問題十四:routing_key和 binding_key 的最大長度是多少?
答:255字節(jié)。問題十五:RabbitMQ 允許發(fā)送的 message 最大可達多大?答:根據(jù) AMQP 協(xié)議規(guī)定,消息體的大小由 64-bit 的值來指定,所以你就可以知道到底能發(fā)多大的數(shù)據(jù)了。
問題十六:什么情況下producer不主動創(chuàng)建 queue 是安全的?
答:1.message是允許丟失的;2.實現(xiàn)了針對未處理消息的 republish 功能(例如采用Publisher Confirm 機制)。
?
問題十七:“dead letter”queue 的用途?
答:當消息被RabbitMQ server投遞到 consumer 后,但 consumer 卻通過 Basic.Reject進行了拒絕時(同時設(shè)置 requeue=false),那么該消息會被放入“dead letter”queue 中。該 queue 可用于排查 message 被 reject 或 undeliver 的原因。
?
問題十八:為什么說保證message被可靠持久化的條件是 queue 和 exchange 具有durable 屬性,同時 message 具有 persistent 屬性才行?
答:binding關(guān)系可以表示為 exchange – binding – queue 。從文檔中我們知道,若要求投遞的 message 能夠不丟失,要求 message 本身設(shè)置 persistent 屬性,要求 exchange和 queue 都設(shè)置 durable 屬性。其實這問題可以這么想,若 exchange 或 queue 未設(shè)置durable 屬性,則在其 crash 之后就會無法恢復(fù),那么即使 message 設(shè)置了 persistent 屬性,仍然存在 message 雖然能恢復(fù)但卻無處容身的問題;同理,若 message 本身未設(shè)置persistent 屬性,則 message 的持久化更無從談起。
?
問題十九:什么情況下會出現(xiàn)blackholed問題?
答:blackholed問題是指,向 exchange 投遞了 message ,而由于各種原因?qū)е略搈essage 丟失,但發(fā)送者卻不知道??蓪?dǎo)致 blackholed 的情況:1.向未綁定 queue 的exchange 發(fā)送 message;2.exchange 以 binding_key key_A 綁定了 queue queue_A,但向該 exchange 發(fā)送 message 使用的 routing_key 卻是 key_B。
?
問題二十:如何防止出現(xiàn)blackholed問題?答:沒有特別好的辦法,只能在具體實踐中通過各種方式保證相關(guān) fabric 的存在。另外,如果在執(zhí)行 Basic.Publish 時設(shè)置 mandatory=true ,則在遇到可能出現(xiàn) blackholed 情況時,服務(wù)器會通過返回 Basic.Return 告之當前 message 無法被正確投遞(內(nèi)含原因 312NO_ROUTE)。
?
問題二十一:Consumer Cancellation Notification機制用于什么場景?答:用于保證當鏡像 queue 中 master 掛掉時,連接到 slave 上的 consumer 可以收到自身 consume 被取消的通知,進而可以重新執(zhí)行 consume 動作從新選出的 master 出獲得消息。若不采用該機制,連接到 slave 上的 consumer 將不會感知 master 掛掉這個事情,導(dǎo)致后續(xù)無法再收到新 master 廣播出來的 message 。另外,因為在鏡像 queue 模式下,存在將 message 進行 requeue 的可能,所以實現(xiàn) consumer 的邏輯時需要能夠正確處理出現(xiàn)重復(fù) message 的情況。
?
問題二十二:Basic.Reject的用法是什么?
答:該信令可用于consumer對收到的 message 進行 reject 。
若在該信令中設(shè)置requeue=true,則當 RabbitMQ server 收到該拒絕信令后,會將該 message 重新發(fā)送到下一個處于 consume 狀態(tài)的 consumer 處(理論上仍可能將該消息發(fā)送給當前consumer)。
若設(shè)置requeue=false,則 RabbitMQ server 在收到拒絕信令后,將直接將該message 從 queue 中移除。另外一種移除 queue 中 message 的小技巧是,consumer 回復(fù) Basic.Ack 但不對獲取到的message 做任何處理。而 Basic.Nack 是對 Basic.Reject 的擴展,以支持一次拒絕多條 message 的能力。
?
問題二十三:為什么不應(yīng)該對所有的message都使用持久化機制?
答:首先,必然導(dǎo)致性能的下降,因為寫磁盤比寫RAM慢的多,message 的吞吐量可能有 10 倍的差距。其次,message 的持久化機制用在 RabbitMQ 的內(nèi)置 cluster 方案時會出現(xiàn)“坑爹”問題。矛盾點在于,若 message 設(shè)置了 persistent 屬性,但 queue 未設(shè)置durable 屬性,那么當該 queue 的 owner node 出現(xiàn)異常后,在未重建該 queue 前,發(fā)往該 queue 的 message 將被 blackholed ;若 message 設(shè)置了 persistent 屬性,同時queue 也設(shè)置了 durable 屬性,那么當 queue 的 owner node 異常且無法重啟的情況下,則該 queue 無法在其他 node 上重建,只能等待其 owner node 重啟后,才能恢復(fù)該 queue 的使用,而在這段時間內(nèi)發(fā)送給該 queue 的 message 將被 blackholed 。所以,是否要對 message 進行持久化,需要綜合考慮性能需要,以及可能遇到的問題。若想達到 100,000 條/秒以上的消息吞吐量(單 RabbitMQ 服務(wù)器),則要么使用其他的方式來確保 message 的可靠 delivery ,要么使用非??焖俚拇鎯ο到y(tǒng)以支持全持久化(例如使用 SSD)。另外一種處理原則是:僅對關(guān)鍵消息作持久化處理(根據(jù)業(yè)務(wù)重要程度),且應(yīng)該保證關(guān)鍵消息的量不會導(dǎo)致性能瓶頸。
重點:RabbitMQ核心概念
·生產(chǎn)者(Producer):發(fā)送消息的應(yīng)用。
·消費者(Consumer):接收消息的應(yīng)用。
·隊列(Queue):存儲消息的緩存。
·消息(Message):又生產(chǎn)者通過RabbitMQ發(fā)送給消費者的信息。
·連接(Connection):連接RabbitMQ和應(yīng)用服務(wù)器的TCP連接。
·通道(Channel):連接里的一個虛擬通道。當你通過消息隊列發(fā)送或者接收消息時,這個操作都是通過通道進行的。
·交換機(Exchange):從生產(chǎn)者那里接收消息,并根據(jù)交換類型分發(fā)到對應(yīng)的消息列隊里。要實現(xiàn)消息的接收,一個隊列必須綁定一個交換機。
·綁定(Binding):綁定是隊列和交換機的一個鏈接。
·路由鍵(Routing Key):路由鍵是供交換機查看并根據(jù)鍵的值來決定如何分發(fā)消息到列隊的一個鍵。路由鍵可以說是消息的目的地址。
·?AMQP:AMQP(高級消息隊列協(xié)議Advanced Message Queuing Protocol)是RabbitMQ使用的消息協(xié)議。
·用戶(Users):在RabbitMQ里,是可以通過指定的用戶名和密碼來進行連接的。每個用戶可以分配不同的權(quán)限,例如讀權(quán)限,寫權(quán)限以及在實例里進行配置的權(quán)限。
?
ConnectionFactory(連接管理器):應(yīng)用程序與Rabbit之間建立連接的管理器,程序代碼中使用;
Channel(信道):消息推送使用的通道;
Exchange(交換器):用于接受、分配消息;
Queue(隊列):用于存儲生產(chǎn)者的消息;
RoutingKey(路由鍵):用于把生成者的數(shù)據(jù)分配到交換器上;
BindingKey(綁定鍵):用于把交換器的消息綁定到隊列上;
?

?