broker 是指一個或多個 erlang node 的邏輯分組,且 node 上執行着 RabbitMQ 應用程式。cluster 是在 broker 的基礎之上,增加了 node 之間共用元數據的約束。
在非 cluster 模式下,元數據主要分爲 Queue 元數據(queue 名字和屬性等)、
Exchange 元數據(exchange 名字、型別和屬性等)、Binding 元數據(存放路由關係的查詢表)、Vhost 元數據(vhost 範圍內針對前三者的命名空間約束和安全屬性設定)。在cluster 模式下,還包括 cluster 中 node 位置資訊和 node 關係資訊。元數據按照 erlang node 的型別確定是僅儲存於 RAM 中,還是同時儲存在 RAM 和 disk 上。元數據在cluster 中是全 node 分佈的。
RAM node 僅將 fabric(即 queue、exchange 和 binding 等 RabbitMQ 基礎構件)相關元數據儲存到記憶體中,但 disk node 會在記憶體和磁碟中均進行儲存。RAM node 上唯一會儲存到磁碟上的元數據是 cluster 中使用的 disk node 的地址。要求在 RabbitMQ cluster中至少存在一個 disk node 。
可以認爲是無限制,因爲限製取決於機器的記憶體,但是訊息過多會導致處理效率的下降。
queue 具有自己的 erlang 進程;exchange 內部實現爲儲存 binding 關係的查詢表;channel 是實際進行路由工作的實體,即負責按照 routing_key 將 message 投遞給queue 。由 AMQP 協定描述可知,channel 是真實 TCP 連線之上的虛擬連線,所有AMQP 命令都是通過 channel 發送的,且每一個 channel 有唯一的 ID。一個 channel 只能被單獨一個操作系統執行緒使用,故投遞到特定 channel 上的 message 是有順序的。但一個操作系統執行緒上允許使用多個 channel 。channel 號爲 0 的 channel 用於處理所有對於當前 connection 全域性有效的幀,而 1-65535 號 channel 用於處理和特定 channel 相關的幀。AMQP 協定給出的 channel 複用模型如下:其中每一個 channel 執行在一個立的執行緒上,多執行緒共用同一個 socket。
vhost 可以理解爲虛擬 broker ,即 mini-RabbitMQ server。其內部均含有獨立的queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的許可權系統,可以做到vhost 範圍的使用者控制。當然,從 RabbitMQ 的全域性角度,vhost 可以作爲不同許可權隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。
當你在單 node 上宣告 queue 時,只要該 node 上相關元數據進行了變更,你就會得到 Queue.Declare-ok 迴應;而在 cluster 上宣告 queue ,則要求 cluster 上的全部node 都要進行元數據成功更新,纔會得到 Queue.Declare-ok 迴應。另外,若 node 型別爲 RAM node 則變更的數據僅儲存在記憶體中,若型別爲 disk node 則還要變更儲存在磁碟上的數據。
是的。用戶端感覺不到有何不同。
不能,在這種情況下,將得到 404 NOT_FOUND 錯誤。只能等 queue 所屬的 node恢復後才能 纔能使用該 queue 。但若該 queue 本身不具有 durable 屬性,則可在其他 node上重新宣告。
若是 consumer 所連線的那個 node 失效(無論該 node 是否爲 consumer 所訂閱queue 的 owner node),則 consumer 會在發現 TCP 連線斷開時,按標準行爲執行重連邏輯,並根據「Assume Nothing」原則重建相應的 fabric 即可。若是失效的 node 爲consumer 訂閱 queue 的 owner node,則 consumer 只能通過 Consumer Cancellation Notification 機制 機製來檢測與該 queue 訂閱關係的終止,否則會出現傻等卻沒有任何訊息來到的問題。
不能。第一,你無法控制所建立的 queue 實際分佈在 cluster 裡的哪個 node 上(一般使用 HAProxy + cluster 模型時都是這樣),這可能會導致各種跨地域存取時的常見問題;第二,Erlang 的 OTP 通訊框架對延遲的容忍度有限,這可能會觸發各種超時,導致業務疲於處理;第三,在廣域網上的連線失效問題將導致經典的「腦裂」問題,而RabbitMQ 目前無法處理(該問題主要是說 Mnesia)。
heavy RPC 是指在業務邏輯中高頻呼叫 RabbitMQ 提供的 RPC 機制 機製,導致不斷建立、銷燬 reply queue ,進而造成 disk node 的效能問題(因爲會針對元數據不斷寫盤)。所以在使用 RPC 機制 機製時需要考慮自身的業務場景。
都會收到 Channel.Close 信令告之不存在(內含原因 404 NOT_FOUND)。
255 位元組。
根據 AMQP 協定規定,訊息體的大小由 64-bit 的值來指定,所以你就可以知道到底能發多大的數據了。
當訊息被 RabbitMQ server 投遞到 consumer 後,但 consumer 卻通過 Basic.Reject進行了拒絕時(同時設定 requeue=false),那麼該訊息會被放入「dead letter」queue 中。該 queue 可用於排查 message 被 reject 或 undeliver 的原因。
binding 關係可以表示爲 exchange – binding – queue 。從文件中我們知道,若要求投遞的 message 能夠不丟失,要求 message 本身設定 persistent 屬性,要求 exchange和 queue 都設定 durable 屬性。其實這問題可以這麼想,若 exchange 或 queue 未設定durable 屬性,則在其 crash 之後就會無法恢復,那麼即使 message 設定了 persistent 屬性,仍然存在 message 雖然能恢復但卻無處容身的問題;同理,若 message 本身未設定persistent 屬性,則 message 的持久化更無從談起。
blackholed 問題是指,向 exchange 投遞了 message ,而由於各種原因導致該message 丟失,但發送者卻不知道。可導致 blackholed 的情況:1.向未系結 queue 的exchange 發送 message;2.exchange 以 binding_key key_A 系結了 queue queue_A但向該 exchange 發送 message 使用的 routing_key 卻是 key_B。
沒有特別好的辦法,只能在具體實踐中通過各種方式保證相關 fabric 的存在。另外,如果在執行 Basic.Publish 時設定 mandatory=true ,則在遇到可能出現 blackholed 情況時,伺服器會通過返回 Basic.Return 告之當前 message 無法被正確投遞(內含原因 312 NO_ROUTE)。
用於保證當映象 queue 中 master 掛掉時,連線到 slave 上的 consumer 可以收到自身 consume 被取消的通知,進而可以重新執行 consume 動作從新選出的 master 出獲得訊息。若不採用該機制 機製,連線到 slave 上的 consumer 將不會感知 master 掛掉這個事情,導致後續無法再收到新 master 廣播出來的 message 。另外,因爲在映象 queue 模式下,存在將 message 進行 requeue 的可能,所以實現 consumer 的邏輯時需要能夠正確處理出現重複 message 的情況。
該信令可用於 consumer 對收到的 message 進行 reject 。若在該信令中設定requeue=true,則當 RabbitMQ server 收到該拒絕信令後,會將該 message 重新發送到下一個處於 consume 狀態的 consumer 處(理論上仍可能將該訊息發送給當前consumer)。若設定 requeue=false ,則 RabbitMQ server 在收到拒絕信令後,將直接將該message 從 queue 中移除。另外一種移除 queue 中 message 的小技巧是,consumer 回覆 回復 Basic.Ack 但不對獲取到的message 做任何處理。而 Basic.Nack 是對 Basic.Reject 的擴充套件,以支援一次拒絕多條 message 的能力。
首先,必然導致效能的下降,因爲寫磁碟比寫 RAM 慢的多,message 的吞吐量可能有 10 倍的差距。其次,message 的持久化機制 機製用在 RabbitMQ 的內建 cluster 方案時會出現「坑爹」問題。矛盾點在於,若 message 設定了 persistent 屬性,但 queue 未設定durable 屬性,那麼當該 queue 的 owner node 出現異常後,在未重建該 queue 前,發往該 queue 的 message 將被 blackholed ;若 message 設定了 persistent 屬性,同時queue 也設定了 durable 屬性,那麼當 queue 的 owner node 異常且無法重新啓動的情況下,則該 queue 無法在其他 node 上重建,只能等待其 owner node 重新啓動後,才能 纔能恢復該 queue 的使用,而在這段時間內發送給該 queue 的 message 將被 blackholed 。所以,是否要對 message 進行持久化,需要綜合考慮效能需要,以及可能遇到的問題。若想達到 100,000 條/秒以上的訊息吞吐量(單 RabbitMQ 伺服器),則要麼使用其他的方式來確保 message 的可靠 delivery ,要麼使用非常快速的儲存系統以支援全持久化(例如使用 SSD)。另外一種處理原則是:僅對關鍵訊息作持久化處理(根據業務重要程度),且應該保證關鍵訊息的量不會導致效能瓶頸。
cluster 是爲了解決當 cluster 中的任意 node 失效後,producer 和 consumer 均可以通過其他 node 繼續工作,即提高了可用性;另外可以通過增加 node 數量增加 cluster的訊息吞吐量的目的。cluster 本身不負責 message 的可靠性問題(該問題由 producer 通過各種機制 機製自行解決);cluster 無法解決跨數據中心的問題(即腦裂問題)。另外,在cluster 前使用 HAProxy 可以解決 node 的選擇問題,即業務無需知道 cluster 中多個node 的 ip 地址。可以利用 HAProxy 進行失效 node 的探測,可以作負載均衡。下圖爲HAProxy + cluster 的模型。
Mirrored queue 是爲了解決使用 cluster 時所建立的 queue 的完整資訊僅存在於單一node 上的問題,從另一個角度增加可用性。若想正確使用該功能,需要保證:
Warrens 是爲了解決 cluster 中 message 可能被 blackholed 的問題,即不能接受producer 不停 republish message 但 RabbitMQ server 無迴應的情況。Warrens 有兩種構成方式,一種模型是兩臺獨立的 RabbitMQ server + HAProxy ,其中兩個 server 的狀態分別爲 active 和 hot-standby 。該模型的特點爲:兩臺 server 之間無任何數據共用和協定互動,兩臺 server 可以基於不同的 RabbitMQ 版本。另一種模型爲兩臺共用儲存的 RabbitMQ server + keepalived ,其中兩個 server 的狀態分別爲 active 和 cold-standby 。該模型的特點爲:兩臺 server 基於共用儲存可以做到完全恢復,要求必須基於完全相同的 RabbitMQ 版本。
Warrens 模型存在的問題:對於第一種模型,雖然理論上講不會丟失訊息,但若在該模型上使用持久化機制 機製,就會出現這樣一種情況,即若作爲 active 的 server 異常後,持久化在該 server 上的訊息將暫時無法被 consume ,因爲此時該 queue 將無法在作爲 hotstandby 的 server 上被重建,所以,只能等到異常的 active server 恢復後,才能 纔能從其上的queue 中獲取相應的 message 進行處理。而對於業務來說,需要具有:a.感知 AMQP 連線斷開後重建各種 fabric 的能力;b.感知 active server 恢復的能力;c.切換回 active server 的時機控制,以及切回後,針對 message 先後順序產生的變化進行處理的能力。對於第二種模型,因爲是基於共用儲存的模式,所以導致 active server 異常的條件,可能同樣會導致 cold-standby server 異常;另外,在該模型下,要求 active 和 cold-standby的 server 必須具有相同的 node 名和 UID ,否則將產生存取許可權問題;最後,由於該模型是冷備方案,故無法保證 cold-standby server 能在你要求的時限內成功啓動。