RabbitMQ 是採用 Erlang 語言實現 AMQP(Advanced Message Queuing Protocol,高級消息隊列協議)的消息中間件,它最初起源於金融系統,用於在分佈式系統中存儲轉發消息。java
RabbitMQ 總體上是一個生產者與消費者模型,主要負責接收、存儲和轉發消息。能夠把消息傳遞的過程想象成:當你將一個包裹送到郵局,郵局會暫存並最終將郵件經過郵遞員送到收件人的手上,RabbitMQ就比如由郵局、郵箱和郵遞員組成的一個系統。從計算機術語層面來講,RabbitMQ 模型更像是一種交換機模型。git
總體模型架構圖
github
Producer(生產者) 和 Consumer(消費者)
RabbitMQ 會根據消息頭把消息發送給感興趣的 Consumer(消費者)架構
Exchange(交換器)
在 RabbitMQ 中,消息並非直接被投遞到 Queue(消息隊列) 中的,中間還必須通過 Exchange(交換器) 這一層,Exchange(交換器) 會把咱們的消息分配到對應的 Queue(消息隊列) 中。分佈式
RabbitMQ 的 Exchange(交換器) 有4種類型,不一樣的類型對應着不一樣的路由策略:direct(默認),fanout, topic, 和 headers,不一樣類型的Exchange轉發消息的策略有所區別。ide
Exchange(交換器) 示意圖以下:性能
生產者將消息發給交換器的時候,通常會指定一個RoutingKey(路由鍵),用來指定這個消息的路由規則,而這個RoutingKey 須要與交換器類型和綁定鍵(BindingKey)聯合使用才能最終生效。ui
RabbitMQ 中經過Binding(綁定)將Exchange(交換器)與Queue(消息隊列)關聯起來,在綁定的時候通常會指定一個BindingKey(綁定鍵),這樣 RabbitMQ 就知道如何正確將消息路由到隊列了,以下圖所示spa
生產者將消息發送給交換器時,須要一個RoutingKey,當 BindingKey 和 RoutingKey 相匹配時,消息會被路由到對應的隊列中。在綁定多個隊列到同一個交換器的時候,這些綁定容許使用相同的 BindingKey。BindingKey 並非在全部的**狀況下都生效,它依賴於交換器類型,好比fanout類型的交換器就會無視,而是將消息路由到全部綁定到該交換器的隊列中。debug
Queue(消息隊列)
Queue(消息隊列) 用來保存消息直到發送給消費者。它是消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列裏面,等待消費者鏈接到這個隊列將其取走。
多個消費者能夠訂閱同一個隊列,這時隊列中的消息會被平均分攤(Round-Robin,即輪詢)給多個消費者進行處理,而不是每一個消費者都收到全部的消息並處理,這樣避免的消息被重複消費。
RabbitMQ不支持隊列層面的廣播消費,若是有廣播消費的需求,須要在其上進行二次開發,這樣會很麻煩,不建議這樣作。
RabbitMQ 經常使用的 Exchange Type 有 fanout、direct、topic、headers 這四種。
fanout
fanout 類型的Exchange路由規則很是簡單,它會把全部發送到該Exchange的消息路由到全部與它綁定的Queue中,不須要作任何判斷操做,因此 fanout 類型是全部的交換機類型裏面速度最快的。fanout 類型經常使用來廣播消息。
direct
direct 類型的Exchange路由規則也很簡單,它會把消息路由到那些 Bindingkey 與 RoutingKey 徹底匹配的 Queue 中。
以上圖爲例,若是發送消息的時候設置路由鍵爲「warning」,那麼消息會路由到 Queue1 和 Queue2。若是在發送消息的時候設置路由鍵爲"Info」或者"debug」,消息只會路由到Queue2。若是以其餘的路由鍵發送消息,則消息不會路由到這兩個隊列中。
direct 類型經常使用在處理有優先級的任務,根據任務的優先級把消息發送到對應的隊列,這樣能夠指派更多的資源去處理高優先級的隊列。
topic
前面講到direct類型的交換器路由規則是徹底匹配 BindingKey 和 RoutingKey ,可是這種嚴格的匹配方式在不少狀況下不能知足實際業務的需求。topic類型的交換器在匹配規則上進行了擴展,它與 direct 類型的交換器類似,也是將消息路由到 BindingKey 和 RoutingKey 相匹配的隊列中,但這裏的匹配規則有些不一樣,它約定:
以上圖爲例:
headers(不推薦)
headers 類型的交換器不依賴於路由鍵的匹配規則來路由消息,而是根據發送的消息內容中的 headers 屬性進行匹配。在綁定隊列和交換器時制定一組鍵值對,當發送消息到交換器時,RabbitMQ會獲取到該消息的 headers(也是一個鍵值對的形式)'對比其中的鍵值對是否徹底匹配隊列和交換器綁定時指定的鍵值對,若是徹底匹配則消息會路由到該隊列,不然不會路由到該隊列。headers 類型的交換器性能會不好,並且也不實用,基本上不會看到它的存在。