一、消息中間件
1.一、什麼是消息中間件
消息中間件(Message Queue Middleware,簡稱 MQ)是指利用高效可靠的消息傳遞機制進行與平臺無關的數據交流,並基於數據通道來進行分佈式系統的集成。java
1.二、消息中間件的做用
- 解耦:在項目啓動之初來預測未來項目會碰到什麼需求,是極其困難的。消息隊列在處理過程當中間插入了一個隱含的、基於數據的接口層,兩邊的處理過程都要實現這一接口。這容許你獨立的擴展或修改兩邊的處理過程,只要確保它們遵照一樣的接口約束。
- 冗餘(存儲):有時在處理數據的時候處理過程會失敗。除非數據被持久化,不然將永遠丟失。消息隊列把數據進行持久化直到它們已經被徹底處理,經過這一方式規避了數據丟失風險。在被許多消息隊列所採用的"插入-獲取-刪除"範式中,在把一個消息從隊列中刪除以前,須要你的處理過程明確的指出該消息已經被處理完畢,確保你的數據被安全的保存直到你使用完畢。
- 擴展性:由於消息中間件解捐了應用的處理過程,因此提升消息入隊和處理的效率是很容 易的,只要另外增長處理過程便可,不須要改變代碼,也不須要調節參數。
- 流量削峯: 在訪問量劇增的狀況下,應用仍然須要繼續發揮做用,可是這樣的突發流 量 並不常 見。若是以能處理這類峯值爲標準而投入資源,無疑是巨大的浪費 。 使用消息中間件可以使關 鍵組件支撐突發訪問壓力,不會由於突發的超負荷請求而徹底崩慣 。
- 可恢復性: 當系統一部分組件失效時,不會影響到整個系統 。 消息中間件下降了進程間的 稿合度,因此即便一個處理消息的進程掛掉,加入消息中間件中的消息仍然能夠在系統恢復後 進行處理 。
- 順序保證: 在大多數使用場景下,數據處理的順序很重要,大部分消息中間件支持必定程 度上的順序性。
- 緩衝: 在任何重要的系統中,都會存在須要不一樣處理時間的元素。消息中間件經過 一個緩 衝層來幫助任務最高效率地執行,寫入消息中間件的處理會盡量快速 。 該緩衝層有助於控制 和優化數據流通過系統的速度。
- 異步通訊: 在不少時候應用不想也不須要當即處理消息 。消息中間件提供了異步處理機制, 容許應用把一些消息放入消息中間件中,但並不當即處理它,在以後須要的時候再慢慢處理 。
1.三、消息中間件的缺點
- 系統可用性下降: 系統中加入了MQ,若是MQ掛了,整套系統奔潰了
- 系統複雜度提升:引入MQ會產生一些問題,好比怎麼保證消息沒有重複消費,怎麼處理消息丟失的狀況等
二、RabbitMQ 簡介
RabbitMQ 是採用 Erlang 語言實現 AMQP (Advanced Message Queuing Protocol,高級消息 隊列協議)的消息中間件。安全
2.一、RabbitMQ 特色
- 可靠性:RabbitMQ 使用一些機制來保證可靠性,如持久性、傳輸確認及發佈確認等
- 靈活的路由: 在消息進入隊列以前,經過交換器來路由消息。對典型的路由功能,RabbitMQ已經提供了一些內置的交換器來實現。針對更復雜的路由功能,能夠將多個交換器綁定在一塊兒,也能夠經過插件機制來實現本身的交換器
- 擴展性: 多個 RabbitMQ 節點能夠組成一個集羣,也能夠根據實際業務狀況動態地擴展集羣中的節點
- 插件機制: RabbitMQ 提供了許多插件,以實現從多方面進行擴展,固然也能夠編寫本身的插件
- 高可用性: 隊列能夠在集羣中的機器上設置鏡像,使得在部分節點出現問題的狀況下隊列任然可用
- 多種協議: RabbitMQ 除了原生支持AMQP協議,還支持STOMP、MQTT等多種消息中間件協議
- 多語言客戶端: RabbitMQ 幾乎支持所用經常使用語言,好比Java、Python、Ruby、PHP等
- 管理界面: RabbitMQ 提供了一個易用的用戶界面,使得用戶能夠監控和管理消息、集羣中的節點等
2.二、相關概念
RabbitMQ 總體上是一個生產者與消費者模型,主要負責接收、存儲和轉發消息。能夠把消 息傳遞的過程想象成:當你將一個包裹送到郵局,郵局會暫存並最終將郵件經過郵遞員送到收 件人的手上, RabbitMQ 就比如由郵局、郵箱和郵遞員組成的一個系統。從計算機術語層面來講, RabbitMQ 模型更像是一種交換機模型。 RabbitMQ 的總體模型架構如圖所示:架構
- Producer: 生產者,就是投遞消息的 一方。
- Consumer: 消費者,就是接收消息的 一方。
- Broker: 消息中間件的服務節點。如圖展現了生產者將消息存入 RabbitMQ Broker,以及消費者從 Broker中消費數據的整個流程
- Queue: 隊列,是 RabbitMQ 的內部對象,用於存儲消息。
- Exchange: 交換器。生產者將消息發送到 Exchange,由交換器將消息路由到一個或者多個隊列中。若是路由不到,或許會返回給生產者,或許直接丟棄。 交換器的具體示意圖如圖所示
- RoutingKey: 路由鍵 。生產者將消息發給交換器 的時候, 通常會 指定 一個 RoutingKey,用 來指定這個消息的路由規則,而這個 RoutingKey 須要與交換器類型和綁定鍵 (BindingKey) 聯 合使用才能最終生效。
- Binding: 綁定 。 RabbitMQ 中經過綁定將交換器與隊列關聯起來,在綁定的時候通常會指定一個綁定鍵 (BindingKey),這樣 RabbitMQ 就知道如何正確地將消息路由到隊列了,如圖所
2.三、交換器類型
RabbitMQ 經常使用的交換器類型有 fanout、 direct、 topic、 headers 這四種 。 異步
- fanout: 它會把全部發送到該交換器的消息路由到全部與該交換器綁定的隊列中。
- direct: 它會把消息路由到那些 BindingKey和 RoutingKey 徹底匹配的隊列中。
- topic: topic類型的交換器在匹配規則上進行了擴展,它與 direct類型的交換器類似,可是它支持模糊匹配,它有以下約定:
- RoutingKey 爲一個點號" "分隔的字符串,好比「com.rabbitmq.client」, "java.util.concurrent", "com.hidden.client"
- BindingKey 和 RoutingKey 同樣也是點號" "分隔的字符串;
- BindingKey 中能夠存在兩種特殊 字符串""和"#",用於作模糊匹配,其中""用於匹配一個單詞,"#"用於匹配多規格單詞(能夠是零個)。
-
- 如圖
- 路由鍵爲" com.rabbitmq.client" 的消息會同時路由到 Queuel 和 Queue2;
- 路由鍵爲" com.hidden.client" 的消息只會路由到 Queue2 中:
- 路由鍵爲" com.hidden.demo" 的消息只會路由到 Queue2 中:
- 路由鍵爲 "java.rabbitmq.demo" 的消息只會路由到 Queuel 中:
- 路由鍵爲" java.util.concurrent" 的消息將會被丟棄或者返回給生產者(須要設置 mandatory 參數) ,由於它沒有匹配任何路由鍵。
- headers: headers 類型的交換器不依賴於路由鍵的匹配規則來路由消息,而是根據發送的消息內容中 的 headers 屬性進行匹配。在綁定隊列和交換器時制定一組鍵值對 , 當發送消息到交換器時, RabbitMQ 會獲取到該消息的 headers (也是一個鍵值對的形式) ,對比其中的鍵值對 是否徹底 匹配隊列和交換器綁定時指定的鍵值對,若是徹底匹配則消息會路由到該隊列,不然不會路由 到該隊列 。 headers 類型的交換器性能會不好,並且也不實用,基本上不會看到它的存在。