二十四個RabbitMQ消息中間件面試題及答案(雙手奉上,拿走不行)

問題一: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ù)按照 erlang

node 的類型確定是僅保存于 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)存和磁盤中均進(jìn)行存儲。RAM node 上唯一

會存儲到磁盤上的元數(shù)據(jù)是 cluster 中使用的 disk node 的地址。要求在 RabbitMQ cluster

中至少存在一個 disk node 。

問題四:RabbitMQ 上的一個 queue 中存放的 message 是否有數(shù)量限制?

答:可以認(rèn)為是無限制,因為限制取決于機(jī)器的內(nèi)存,但是消息過多會導(dǎo)致處理效率的下

降。

問題五:RabbitMQ 概念里的 channel、exchange 和 queue 這些東東是邏輯概念,還是對應(yīng)著進(jìn)程實體?這些東東分別起什么作用?

答:queue 具有自己的 erlang 進(jìn)程;exchange 內(nèi)部實現(xiàn)為保存 binding 關(guān)系的查找表;

channel 是實際進(jìn)行路由工作的實體,即負(fù)責(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 用于處理所有

對于當(dāng)前 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 范圍的用戶控制。當(dāng)然,從 RabbitMQ 的全局角度,vhost 可以作為不同權(quán)限隔離

的手段(一個典型的例子就是不同的應(yīng)用可以跑在不同的 vhost 中)。

【cluster 相關(guān)】

問題七:在單 node 系統(tǒng)和多 node 構(gòu)成的 cluster 系統(tǒng)中聲明 queue、exchange ,以及

進(jìn)行 binding 會有什么不同?

答:當(dāng)你在單 node 上聲明 queue 時,只要該 node 上相關(guān)元數(shù)據(jù)進(jìn)行了變更,你就會

得到 Queue.Declare-ok 回應(yīng);而在 cluster 上聲明 queue ,則要求 cluster 上的全部

node 都要進(jìn)行元數(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 連接斷開時,按標(biāo)準(zhǔn)行為執(zhí)行重連

邏輯,并根據(jù)“Assume Nothing”原則重建相應(yīng)的 fabric 即可。若是失效的 node 為

consumer 訂閱 queue 的 owner node,則 consumer 只能通過 Consumer Cancellation

Notification 機(jī)制來檢測與該 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)。

【綜合問題】

問題十二:為什么 heavy RPC 的使用場景下不建議采用 disk node ?

答:heavy RPC 是指在業(yè)務(wù)邏輯中高頻調(diào)用 RabbitMQ 提供的 RPC 機(jī)制,導(dǎo)致不斷創(chuàng)建、

銷毀 reply queue ,進(jìn)而造成 disk node 的性能問題(因為會針對元數(shù)據(jù)不斷寫盤)。所以

在使用 RPC 機(jī)制時需要考慮自身的業(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 最大可達(dá)多大?

答:根據(jù) AMQP 協(xié)議規(guī)定,消息體的大小由 64-bit 的值來指定,所以你就可以知道到底

能發(fā)多大的數(shù)據(jù)了。

問題十六:什么情況下 producer 不主動創(chuàng)建 queue 是安全的?

答:1.message 是允許丟失的;2.實現(xiàn)了針對未處理消息的 republish 功能(例如采用

Publisher Confirm 機(jī)制)。

問題十七:“dead letter”queue 的用途?

答:當(dāng)消息被 RabbitMQ server 投遞到 consumer 后,但 consumer 卻通過 Basic.Reject

進(jìn)行了拒絕時(同時設(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ū)е略?/p>

message 丟失,但發(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 告之當(dāng)前 message 無法被正確投遞(內(nèi)含原因 312

NO_ROUTE)。

問題二十一:Consumer Cancellation Notification 機(jī)制用于什么場景?

答:用于保證當(dāng)鏡像 queue 中 master 掛掉時,連接到 slave 上的 consumer 可以收到自

身 consume 被取消的通知,進(jìn)而可以重新執(zhí)行 consume 動作從新選出的 master 出獲得

消息。若不采用該機(jī)制,連接到 slave 上的 consumer 將不會感知 master 掛掉這個事

情,導(dǎo)致后續(xù)無法再收到新 master 廣播出來的 message 。另外,因為在鏡像 queue 模

式下,存在將 message 進(jìn)行 requeue 的可能,所以實現(xiàn) consumer 的邏輯時需要能夠正

確處理出現(xiàn)重復(fù) message 的情況。

問題二十二:Basic.Reject 的用法是什么?

答:該信令可用于 consumer 對收到的 message 進(jìn)行 reject 。若在該信令中設(shè)置

requeue=true,則當(dāng) RabbitMQ server 收到該拒絕信令后,會將該 message 重新發(fā)送到下

一個處于 consume 狀態(tài)的 consumer 處(理論上仍可能將該消息發(fā)送給當(dāng)前

consumer)。若設(shè)置 requeue=false ,則 RabbitMQ server 在收到拒絕信令后,將直接將該

message 從 queue 中移除。

另外一種移除 queue 中 message 的小技巧是,consumer 回復(fù) Basic.Ack 但不對獲取到的

message 做任何處理。

而 Basic.Nack 是對 Basic.Reject 的擴(kuò)展,以支持一次拒絕多條 message 的能力。

問題二十三:為什么不應(yīng)該對所有的 message 都使用持久化機(jī)制?

答:首先,必然導(dǎo)致性能的下降,因為寫磁盤比寫 RAM 慢的多,message 的吞吐量可能

有 10 倍的差距。其次,message 的持久化機(jī)制用在 RabbitMQ 的內(nèi)置 cluster 方案時會

出現(xiàn)“坑爹”問題。矛盾點在于,若 message 設(shè)置了 persistent 屬性,但 queue 未設(shè)置

durable 屬性,那么當(dāng)該 queue 的 owner node 出現(xiàn)異常后,在未重建該 queue 前,發(fā)

往該 queue 的 message 將被 blackholed ;若 message 設(shè)置了 persistent 屬性,同時

queue 也設(shè)置了 durable 屬性,那么當(dāng) queue 的 owner node 異常且無法重啟的情況

下,則該 queue 無法在其他 node 上重建,只能等待其 owner node 重啟后,才能恢復(fù)

該 queue 的使用,而在這段時間內(nèi)發(fā)送給該 queue 的 message 將被 blackholed 。所

以,是否要對 message 進(jìn)行持久化,需要綜合考慮性能需要,以及可能遇到的問題。若想

達(dá)到 100,000 條/秒以上的消息吞吐量(單 RabbitMQ 服務(wù)器),則要么使用其他的方式來

確保 message 的可靠 delivery ,要么使用非??焖俚拇鎯ο到y(tǒng)以支持全持久化(例如使

用 SSD)。另外一種處理原則是:僅對關(guān)鍵消息作持久化處理(根據(jù)業(yè)務(wù)重要程度),且應(yīng)

該保證關(guān)鍵消息的量不會導(dǎo)致性能瓶頸。

問題二十四:RabbitMQ 中的 cluster、mirrored queue,以及 warrens 機(jī)制分別用于解決什么問題?存在哪些問題?

答:cluster 是為了解決當(dāng) cluster 中的任意 node 失效后,producer 和 consumer 均可以

通過其他 node 繼續(xù)工作,即提高了可用性;另外可以通過增加 node 數(shù)量增加 cluster

的消息吞吐量的目的。cluster 本身不負(fù)責(zé) message 的可靠性問題(該問題由 producer 通

過各種機(jī)制自行解決);cluster 無法解決跨數(shù)據(jù)中心的問題(即腦裂問題)。另外,在

cluster 前使用 HAProxy 可以解決 node 的選擇問題,即業(yè)務(wù)無需知道 cluster 中多個

node 的 ip 地址??梢岳?HAProxy 進(jìn)行失效 node 的探測,可以作負(fù)載均衡。下圖為

HAProxy + cluster 的模型。

Mirrored queue 是為了解決使用 cluster 時所創(chuàng)建的 queue 的完整信息僅存在于單一

node 上的問題,從另一個角度增加可用性。若想正確使用該功能,需要保證:1.consumer

需要支持 Consumer Cancellation Notification 機(jī)制;2.consumer 必須能夠正確處理重復(fù)

message 。

Warrens 是為了解決 cluster 中 message 可能被 blackholed 的問題,即不能接受

producer 不停 republish message 但 RabbitMQ server 無回應(yīng)的情況。Warrens 有兩種構(gòu)

成方式,一種模型是兩臺獨立的 RabbitMQ server + HAProxy ,其中兩個 server 的狀態(tài)分

別為 active 和 hot-standby 。該模型的特點為:兩臺 server 之間無任何數(shù)據(jù)共享和協(xié)議

交互,兩臺 server 可以基于不同的 RabbitMQ 版本。如下圖所示

另一種模型為兩臺共享存儲的 RabbitMQ server + keepalived ,其中兩個 server 的狀態(tài)分

別為 active 和 cold-standby 。該模型的特點為:兩臺 server 基于共享存儲可以做到完全

恢復(fù),要求必須基于完全相同的 RabbitMQ 版本。如下圖所示

Warrens 模型存在的問題:對于第一種模型,雖然理論上講不會丟失消息,但若在該模型

上使用持久化機(jī)制,就會出現(xiàn)這樣一種情況,即若作為 active 的 server 異常后,持久化

在該 server 上的消息將暫時無法被 consume ,因為此時該 queue 將無法在作為 hot-

standby 的 server 上被重建,所以,只能等到異常的 active server 恢復(fù)后,才能從其上的

queue 中獲取相應(yīng)的 message 進(jìn)行處理。而對于業(yè)務(wù)來說,需要具有:a.感知 AMQP 連

接斷開后重建各種 fabric 的能力;b.感知 active server 恢復(fù)的能力;c.切換回 active

server 的時機(jī)控制,以及切回后,針對 message 先后順序產(chǎn)生的變化進(jìn)行處理的能力。

對于第二種模型,因為是基于共享存儲的模式,所以導(dǎo)致 active server 異常的條件,可能

同樣會導(dǎo)致 cold-standby server 異常;另外,在該模型下,要求 active 和 cold-standby

的 server 必須具有相同的 node 名和 UID ,否則將產(chǎn)生訪問權(quán)限問題;最后,由于該模

型是冷備方案,故無法保證 cold-standby server 能在你要求的時限內(nèi)成功啟動。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容