淺談對RabbitMQ的認識

一.什麼是消息隊列?何時使用它web


  在傳統的web架構中(此處特指Java SSM架構),用戶在web中進行了某項須要和後臺產生交互的操做後,通常都要開啓一個session,從view層開始,由controller層尋找相應的模型構件,找到相應的model後,生成相應的Java bean,再由Spring將bean映射到邏輯層,找到相關業務邏輯後,調用持久層框架,由數據庫進行數據操做。能夠看出,實際的業務邏輯十分複雜,在業務邏輯很少時尚可接受,但因爲大多數數據庫更新採用的是串行的方式,全部操做都須要在上一個操做完成後才能開始,就拿最多見的註冊帳號操做來講,常規操做下,用戶輸入基本信息之後,服務器響應時間咱們假設爲50ms,驗證驗證碼的正確也須要50ms,驗證手機號或者郵箱一樣須要50ms,那麼加起來就須要150ms。能夠看出,在數據庫操做數量增大後,即便是一個很是簡單的select操做,也須要產生不小的服務器負擔,一旦業務量也同時增大,極可能會形成服務器卡頓甚至宕機,給用戶帶來極差的體驗。而以前的解決方法,是使用cookie技術,即將數據存放到客戶端的瀏覽器上,但cookie技術雖然簡化了業務流程,隨之而來的是安全性的下降。某些居心不良的用戶可能會修改本地cookie,具備很大的安全隱患。(補充一句,也能夠經過對SQL自己的優化,經過調整行級鎖來達到最佳的鎖粒性,具體能夠參考《高性能mySQL》一書,本文不作贅述。)shell

  所以,咱們引入了消息中間件(Message-oriented middleware,MOM)技術。消息代理服務器經過將用戶消息暫存到一個消息容器中,將一系列複雜的業務流程進行解耦,每一個模塊只須要完成它對應的功能,不須要關心別的模塊。畫一張圖以便你們理解。數據庫

  能夠看到,經過使用MOM技術,咱們將本來可能須要150ms的業務流程縮短到了只須要70ms(實際上優化的時間會更多,由於RabbitMQ的特點正是響應時間極短,達到了微秒級)。同時,實現了業務的解耦,驗證手機號時不須要關心用戶此時有沒有經過驗證碼。固然,若是併發量太大,咱們能夠在超過消息隊列最大吞吐量後,選擇拋棄用戶請求,或者直接將用戶重定向至報錯頁面。根據採用技術的不一樣,最大吞吐量也有所不一樣,本文介紹的RabbitMQ可達到萬級,若是併發量大於萬級,能夠採用Kafka等技術。瀏覽器

  固然,一種技術不可能只有優勢而沒有缺點。我我的對MOM的理解是這樣的,首先它確實對高併發場景有很大的幫助,好比雙十一等訪問量激增的時候,能夠有效幫助服務器進行錯峯。同時對各模塊進行解耦,使系統各模塊間的依賴度下降,不至於一個模塊掛了整個系統所有癱瘓。最後,MOM是一種異步請求,無需服務器響應就能夠發送下一個請求。可是,與之伴生的是,它對服務器壓力的激增,和一系列的現實問題。我打個比方,就拿雙十一搶購來講,假如採用了MOM技術,用戶下的訂單被存在消息隊列服務器上,此時,若是後臺的庫存臨時出現變化了,好比某我的下了不少訂單忽然退單了,因爲數據還沒有存入數據庫,其可能會產生一些影響,又或者說在後續的某個部分, 好比你下了訂單之後,後續的手機號填錯了,此時你已經經過了下單模塊,訂單信息已經存入了消息隊列服務器中,但後續本該異步的出現了錯誤,那可能就會出現髒讀的狀況。固然這些問題都是能夠經過一 系列預案,用複雜的邏輯判斷來規避的,但勢必增長了系統出錯的風險,由於系統的複雜性被大大地增長了。更須要注意的是,雖然系統各模塊間的依賴度下降了,但這是創建在對消息隊列服務器的依賴上的,若是消息隊列服務器掛了呢?因此,每項技術都有其應用場景,咱們應該根據實際使用狀況,來具體分析要不要使用MOM技術。安全

 

二.AMQ協議服務器


 

  RabbitMQ基於AMQP規範,AMQP規範不只定義了一種網絡協議,也定義了服務器端的服務和行爲。這就是高級消息隊列(Advanced Message Queuing,AMQ)模型,其在邏輯上定義了三種抽象組件用於指定消息的路由行爲:cookie

·交換器(Exchange),消息代理服務器中用於把消息路由到隊列的組件。網絡

·隊列(Queue),用來存儲消息的數據結構,位於硬盤或內存中。session

·綁定(Binding),一套規則,用於告訴交換器消息應該被存儲到哪一個隊列。數據結構

  一個AMQP能夠有多個信道,容許服務器和客戶端之間進行屢次通訊,這就是多路複用。須要注意的是,在嘗試聲明一個與現有隊列同名的信道時,若是新隊列的屬性與現有隊列不同,那麼RabbitMQ將關閉RPC請求的信道。 要正確處理錯誤,你的客戶端應用程序應該監聽來自RabbitMQ的Channel.Close命令,以便可以正確響應。有的客戶端可能會經過在Channel.Close命令註冊一個回調方法來自動觸發。

  低層AMQP幀是由五個不一樣的組件構成的,其分別是:

 ·   幀類型
 ·   信道編號
 ·   以字節爲單位的幀大小
 ·   幀有效載荷
 ·   結束字節標記(ASCII值206)
  低層AMQP幀的頭部是三個字段,這三個字段組合起來被稱爲幀頭。第一個字段是指示幀類型的單個字節,第二個字段指定幀的信道,第三個字段攜帶幀有效載荷的字節大小。
 
  在幀內部,位於頭部以後和結束字節標記以前的內容就是幀的有效載荷。幀的設計是爲了保護其攜帶內容的完整性。 
 
  AMQP的幀類型一樣分爲五種:協議頭幀,方法幀,內容頭幀,消息體幀,心跳幀。其中協議頭幀用於鏈接到RabbitMQ,僅使用一次。方法幀攜帶發送給RabbitMQ或從RabbitMQ接收到的RPC請求或響應。內容頭幀包含一條信息的大小和屬性。消息體幀包含消息的內容。心跳幀在客戶端與RabbitMQ之間進行傳遞,做爲一種校驗機制確保鏈接的兩端均可用,且均在正常工做。 

三.RabbitMQ集羣
  消息隊列中間件技術是分佈式系統中的重要組件,所以,咱們須要對RabbitMQ集羣有必定的認識。維護集羣所需的工做和開銷與集羣中節點的數量多少有關,通俗一點來講,也就是越大的系統,就須要佔用越多的額外資源對其進行管理,其遵循木桶原理,與集羣中最慢的那個節點的響應速度有關。通常來講,RabbitMQ集羣至少須要兩個節點,至多在32-64個之間,由於其系統的複雜度是非線性上升的,系統中的每個節點都須要瞭解其餘節點的狀況,這致使了你每添加一個新的節點,複雜性就會成指數化上升。不過,官方提供了一個工具,RabbitMQ UI,來解決這一問題,其能夠很好地管理大型RabbitMQ集羣。
  此外,向RabbitMQ添加的節點必須是磁盤節點或者內存節點。若是集羣擁有大量的運行時狀態時,相比內存節點,磁盤節點更容易收到磁盤I/O的影響。
內存節點僅將運行時狀態信息存儲在內存數據庫中。能夠說兩種存儲方式各有優劣,須要開發人員根據實際需求去進行判斷。須要注意的是,集羣裏至少應當存在一個磁盤節點,由於一旦集羣出現問題崩潰,崩潰的內存節點再次加入集羣時,不會包含任何以前存儲的信息,換而言之,這就是一個全新加入的節點,所以,須要磁盤節點將配置信息發送給它,若是有多個磁盤節點,那麼應該把整個集羣都關閉,再按照順序重啓節點,優先啓動擁有最多正確狀態的那個節點。
  有兩種方式向集羣中添加節點,其一是修改rabbitmq.cfg文件,來定義集羣中的每一個節點。由於有不少自動配置管理工具,好比Chef,Puppet等,這種方式更簡單且不容易出錯。第二種方式是經過使用cmd或者shell命令行來添加節點,這種方法工做量大,且相對來講不嚴格,但更有助於操做人員瞭解集羣降級問題的排查,有興趣的朋友能夠自行了解一下erlang cookie及其對RabbitMQ集羣的應用。
 
結束語
  本人的第一篇技術博客就暫時到此爲止,本文僅涉及到原理和應用部分,但願本身之後有空詳細講一下RabbitMQ如何實際開發(但願懶癌之後每週都能更新一篇博客啦)另外有不正之處也望各位大神能多多指教,畢竟這是個人一家之言,其確定有不足之處。 本文系我原創,如需轉載,請聯繫我本人,並註明出處,若有侵權,必追究其法律責任。
 
參考書目:
Gavin M.Roy.RabbitMQ in Depth[M],2018.6,21-24.
相關文章
相關標籤/搜索