你們平時也有用到一些消息中間件(MQ),可是對其理解可能僅停留在會使用 API 能實現生產消息、消費消息就完事了。面試
對 MQ 更加深刻的問題,可能不少人沒怎麼思考過。今天以RabbitMQ爲例,和你們一塊兒深刻了解MQ。數據庫
RabbitMQ 是一個由 Erlang 語言開發的 AMQP 的開源實現。服務器
AMQP :Advanced Message Queue,高級消息隊列協議。它是應用層協議的一個開放標準,爲面向消息的中間件設計,基於此協議的客戶端與消息中間件可傳遞消息,並不受產品、開發語言等條件的限制。網絡
RabbitMQ 最初起源於金融系統,用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。具體特色包括:數據結構
RabbitMQ 架構架構
使用場景併發
在咱們秒殺搶購商品的時候,系統會提醒咱們稍等排隊中,而不是像幾年前同樣頁面卡死或報錯給用戶。異步
像這種排隊結算就用到了消息隊列機制,放入通道里面一個一個結算處理,而不是某個時間斷忽然涌入大批量的查詢新增把數據庫給搞宕機,因此RabbitMQ本質上起到的做用就是削峯填谷,爲業務保駕護航。分佈式
如今的市面上有不少MQ能夠選擇,好比ActiveMQ、ZeroMQ、Appche Qpid,那問題來了爲何要選擇RabbitMQ?微服務
除了Qpid,RabbitMQ是惟一一個實現了AMQP標準的消息服務器;
可靠性,RabbitMQ的持久化支持,保證了消息的穩定性;
高併發,RabbitMQ使用了Erlang開發語言,Erlang是爲電話交換機開發的語言,天生自帶高併發光環,和高可用特性;
集羣部署簡單,正是應爲Erlang使得RabbitMQ集羣部署變的超級簡單;
社區活躍度高,根據網上資料來看,RabbitMQ也是首選;
生產者、消費者和代理
在瞭解消息通信以前首先要了解3個概念:生產者、消費者和代理。
消息發送原理
首先你必須鏈接到Rabbit才能發佈和消費消息,那怎麼鏈接和發送消息的呢?
你的應用程序和Rabbit Server之間會建立一個TCP鏈接,一旦TCP打開,並經過了認證,認證就是你試圖鏈接Rabbit以前發送的Rabbit服務器鏈接信息和用戶名和密碼,有點像程序鏈接數據庫,使用Java有兩種鏈接認證的方式,後面代碼會詳細介紹,一旦認證經過你的應用程序和Rabbit就建立了一條AMQP信道(Channel)。
信道是建立在「真實」TCP上的虛擬鏈接,AMQP命令都是經過信道發送出去的,每一個信道都會有一個惟一的ID,不管是發佈消息,訂閱隊列或者介紹消息都是經過信道完成的。
對於操做系統來講建立和銷燬TCP會話是很是昂貴的開銷,假設高峯期每秒有成千上萬條鏈接,每一個鏈接都要建立一條TCP會話,這就形成了TCP鏈接的巨大浪費,並且操做系統每秒能建立的TCP也是有限的,所以很快就會遇到系統瓶頸。
若是咱們每一個請求都使用一條TCP鏈接,既知足了性能的須要,又能確保每一個鏈接的私密性,這就是引入信道概念的緣由。
你必須知道的Rabbit
想要真正的瞭解Rabbit有些名詞是你必須知道的。
包括:ConnectionFactory(鏈接管理器)、Channel(信道)、Exchange(交換器)、Queue(隊列)、RoutingKey(路由鍵)、BindingKey(綁定鍵)。
看到上面的解釋,最難理解的路由鍵和綁定鍵了,那麼他們具體怎麼發揮做用的,請看下圖:
關於更多交換器的信息,咱們在後面再講。
消息持久化
Rabbit隊列和交換器有一個不可告人的祕密,就是默認狀況下重啓服務器會致使消息丟失,那麼怎麼保證Rabbit在重啓的時候不丟失呢?答案就是消息持久化。
當你把消息發送到Rabbit服務器的時候,你須要選擇你是否要進行持久化,但這並不能保證Rabbit能從崩潰中恢復,想要Rabbit消息能恢復必須知足3個條件:
投遞消息的時候durable設置爲true,消息持久化,代碼:channel.queueDeclare(x, true, false, false, null),參數2設置爲true持久化;
設置投遞模式deliveryMode設置爲2(持久),代碼:channel.basicPublish(x, x, MessageProperties.PERSISTENT_TEXT_PLAIN,x),參數3設置爲存儲純文本到磁盤;
消息已經到達持久化交換器上;
消息已經到達持久化的隊列;
持久化工做原理
Rabbit會將你的持久化消息寫入磁盤上的持久化日誌文件,等消息被消費以後,Rabbit會把這條消息標識爲等待垃圾回收。
持久化的缺點
消息持久化的優勢顯而易見,但缺點也很明顯,那就是性能,由於要寫入硬盤要比寫入內存性能較低不少,從而下降了服務器的吞吐量,儘管使用SSD硬盤可使事情獲得緩解,但他仍然吸乾了Rabbit的性能,當消息成千上萬條要寫入磁盤的時候,性能是很低的。
因此使用者要根據本身的狀況,選擇適合本身的方式。
使用了 MQ 以後,還要關心消息丟失的問題。這裏咱們挑 RabbitMQ 來講明一下吧。
生產者弄丟了數據
RabbitMQ 生產者將數據發送到 RabbitMQ 的時候,可能數據在網絡傳輸中搞丟了,這個時候 RabbitMQ 收不到消息,消息就丟了。
RabbitMQ 提供了兩種方式來解決這個問題:
事務方式:在生產者發送消息以前,經過`channel.txSelect`開啓一個事務,接着發送消息。
若是消息沒有成功被 RabbitMQ 接收到,生產者會收到異常,此時就能夠進行事務回滾`channel.txRollback`,而後從新發送。假如 RabbitMQ 收到了這個消息,就能夠提交事務`channel.txCommit`。
可是這樣一來,生產者的吞吐量和性能都會下降不少,如今通常不這麼幹。
另一種方式就是經過 Confirm 機制:這個 Confirm 模式是在生產者那裏設置的,就是每次寫消息的時候會分配一個惟一的 ID,而後 RabbitMQ 收到以後會回傳一個 ACK,告訴生產者這個消息 OK 了。
若是 RabbitMQ 沒有處理到這個消息,那麼就回調一個 Nack 的接口,這個時候生產者就能夠重發。
事務機制和 Confirm 機制最大的不一樣在於事務機制是同步的,提交一個事務以後會阻塞在那兒。
可是 Confirm 機制是異步的,發送一個消息以後就能夠發送下一個消息,而後那個消息 RabbitMQ 接收了以後會異步回調你一個接口通知你這個消息接收到了。
因此通常在生產者這塊避免數據丟失,都是用 Confirm 機制的。
RabbitMQ 弄丟了數據
RabbitMQ 集羣也會弄丟消息,這個問題在官方文檔的教程中也提到過,就是說在消息發送到 RabbitMQ 以後,默認是沒有落地磁盤的,萬一 RabbitMQ 宕機了,這個時候消息就丟失了。
因此爲了解決這個問題,RabbitMQ 提供了一個持久化的機制,消息寫入以後會持久化到磁盤。
這樣哪怕是宕機了,恢復以後也會自動恢復以前存儲的數據,這樣的機制能夠確保消息不會丟失。
設置持久化有兩個步驟:
第一個是建立 Queue 的時候將其設置爲持久化的,這樣就能夠保證 RabbitMQ 持久化 Queue 的元數據,可是不會持久化 Queue 裏的數據。
第二個是發送消息的時候將消息的 deliveryMode 設置爲 2,就是將消息設置爲持久化的,此時 RabbitMQ 就會將消息持久化到磁盤上去。
可是這樣一來可能會有人說:萬一消息發送到 RabbitMQ 以後,還沒來得及持久化到磁盤就掛掉了,數據也丟失了,怎麼辦?
對於這個問題,實際上是配合上面的 Confirm 機制一塊兒來保證的,就是在消息持久化到磁盤以後纔會給生產者發送 ACK 消息。
萬一真的遇到了那種極端的狀況,生產者是能夠感知到的,此時生產者能夠經過重試發送消息給別的 RabbitMQ 節點。
消費端弄丟了數據
RabbitMQ 消費端弄丟了數據的狀況是這樣的:在消費消息的時候,剛拿到消息,結果進程掛了,這個時候 RabbitMQ 就會認爲你已經消費成功了,這條數據就丟了。
對於這個問題,要先說明一下 RabbitMQ 消費消息的機制:在消費者收到消息的時候,會發送一個 ACK 給 RabbitMQ,告訴 RabbitMQ 這條消息被消費到了,這樣 RabbitMQ 就會把消息刪除。
可是默認狀況下這個發送 ACK 的操做是自動提交的,也就是說消費者一收到這個消息就會自動返回 ACK 給 RabbitMQ,因此會出現丟消息的問題。
因此針對這個問題的解決方案就是:關閉 RabbitMQ 消費者的自動提交 ACK,在消費者處理完這條消息以後再手動提交 ACK。
這樣即便遇到了上面的狀況,RabbitMQ 也不會把這條消息刪除,會在你程序重啓以後,從新下發這條消息過來。
看完點贊,感謝您的承認;
隨手轉發,分享知識,讓更多人學習到;
記得點關注,天天更新的!!!
因爲篇幅緣由,在這作不了所有展現,只是講解了一些RabbitMQ的內容,我整理了多份pdf文檔免費分享給那些有須要的朋友。
裏面的內容包括但不限於一下內容(這是其中一份文檔目錄截圖,附有面試題含答案以及知識點講解):
同時整理也花費了蠻多時間,在這把這些pdf分享給你們,以爲有用有須要的朋友的能夠加羣:1017599436便可獲取免費領取方式!!!文檔中有他的知識點的高頻面試點答疑,很是詳細!!!
同時還有一份Java中高級面試高頻考點文檔免費分享給你們,與上面那份文檔掌握其中的大部分知識足以面對不少互聯網公司包括阿里螞蟻金服等面試了。
其中囊括了JVM、鎖、併發、Java反射、Spring原理、微服務、Zookeeper、數據庫、數據結構等大量知識點。
記得必定要轉發!!
更多Java進階知識筆記文檔分享,這些對於面試仍是學習來講都是一份不錯的學習資料
以爲有用有須要的朋友的能夠加羣:1017599436便可獲取免費領取方式!