1. 程式人生 > >rocketmq學習(一) rocketmq介紹與安裝

rocketmq學習(一) rocketmq介紹與安裝

1.訊息佇列介紹

  訊息佇列本質上來說是一個符合先進先出原則的單向佇列:一方傳送訊息並存入訊息佇列尾部(生產者投遞訊息),一方從訊息佇列的頭部取出訊息(消費者消費訊息)。但對於一個成熟可靠的訊息佇列來說,所需要解決的主要問題還包括:高效可靠的訊息投遞、儲存;能承受高併發的流量衝擊,可通過叢集部署來解決單點故障等等。

  由於訊息佇列具備了以上特點,因此在如今的微服務架構中能夠作為一種中介軟體,提供許多重要的功能以解決微服務架構中的諸多痛點:

1.應用解耦

  微服務架構中,存在著眾多子系統,共同完成對外部使用者的服務。

  舉個例子:當用戶在訂單系統下單時,訂單子系統除了需要執行自己系統的業務邏輯之外,可能還需要呼叫庫存子系統去扣減庫存;呼叫會員子系統去增加使用者的積分;呼叫資料分析子系統去插入使用者下單的分析資料等等。使用者的一個下單行為橫跨了N個業務子系統,如果按照傳統的同步序列方式一個接一個的呼叫,使用者的下單操作將會執行較長的時間,對使用者不友好。同時,由於是同步呼叫,一旦某一個子系統出現了宕機,訪問超時等問題,整個下單業務都將陷入癱瘓。

  訊息佇列可以將同步的系統呼叫轉為非同步的訊息投遞,一定程度上解除業務子系統間的耦合。當訂單子系統執行完本地邏輯後,只需傳送一個標識下單成功的訊息,讓下游依賴的子系統訂閱此訊息,消費處理訊息來完成對應的業務。這樣,使用者的下單操作將很快完成,也不必擔心下游子系統的故障會波及到訂單系統。

  雖然訊息佇列解除了業務子系統間的耦合,但同時也讓業務子系統對訊息佇列系統有了很強的依賴關係,如果訊息隊列出現了故障,業務系統將會出現嚴重故障。

  但由於訊息佇列在設計之初的目的十分簡單明確:就是為了可靠的收發訊息。因此其可用性,穩定性比絕大多數業務系統要高的多。天下沒有免費的午餐,在微服務系統中引入訊息佇列依然是利大於弊的。

2.流量削峰

  大多數系統的訪問流量並不是一天24小時均勻穩定的,而是存在著一定的突發性。例如電商的秒殺活動,系統配置在平時能承受住500qps,可在進行秒殺活動時,瞬時的qps可能達到了5000,為平常的10倍,如果不進行處理防護,將會導致服務癱瘓。

  可以選擇擴容伺服器來應對可能的高峰流量,但擴容的伺服器在秒殺活動過去之後多數會被閒置,從而造成很大的浪費;也可以設定併發的閾值,在訪問併發數達到一定程度時就進行熔斷限流,拒絕手慢的秒殺使用者下單,可這樣會讓使用者體驗很差。

  這時,訊息佇列就能派上用場了。我們可以在系統中使用訊息佇列作為緩衝,將每一個使用者下單請求都作為一條訊息存入訊息佇列,訊息佇列會根據消費者的消費速度以一種穩定的方式將流量傳遞給下游消費者系統,在消費者系統處理完下單操作後非同步的通知使用者下單結果。雖然使用者可能會延遲一段時間才能得到反饋,但無論如何也比無法下單要好。

  訊息佇列就像一個漏桶,可以將瞬時的尖峰流量快取起來,並以一種穩定的速度傳遞給下游消費者,從而達到流量削峰的目的。

3.訊息分發

  沿用之前的例子,訂單子系統的下單成功操作在業務上可能有許多其它系統需要對其做出響應(扣庫存,加積分,核銷優惠券等等)。

  按照傳統的方式,需要訂單系統挨個呼叫其它子系統的介面。隨著業務的變化,每當有新的子系統需要對下單成功操作做出響應時,就需要改動訂單系統的程式碼邏輯去適應新的需求。

   而如果引入了訊息佇列,則可以在下單成功之後由訂單系統傳送一條訊息,讓感興趣的其它子系統去訂閱下單成功訊息。如果新的系統也出現了依賴下單成功動作的需求,自行訂閱對應訊息即可,並不需要訂單系統做出任何的改變。

  可以利用訊息分發機制可以實現程式碼邏輯的解耦。

2.Rocketmq介紹

  rocketmq是阿里巴巴團隊使用java語言開發的一款分散式訊息中介軟體,是一款低延遲,高可用,擁有海量訊息堆積能力和靈活拓展性的訊息佇列。

2.1 rocketmq組成部分

  rocketmq由四大核心模組組成:producer、consumer、brokerServer、nameServer。其中brokerServer和nameServer是rocketmq的服務端,兩者一起獨立的對外提供服務;而producer和consumer可看做是rocketmq的客戶端,一般依附於業務應用程式。

1. Producer

  producer負責傳送訊息。使用producer將訊息傳送到brokerServer,由brokerServer統一進行訊息的分發。

  rocketmq支援多種訊息傳送方式,如同步訊息傳送、非同步回撥訊息傳送、順序訊息傳送以及單向訊息傳送(非同步無回撥)。除了單向訊息傳送,其餘的傳送方式均需要brokerServer返回傳送結果的確認訊息。

  特別的,rocketmq的一大特色是支援傳送事務訊息(半訊息),能一定程度上解決分散式事務的問題。

2. Consumer

  consumer 負責消費producer傳送的訊息。consumer會從brokerServer獲取訊息,並傳遞給應用程式。

  rocketMQ使用的訊息原語是At Least Once(至少一次成功消費),如果一定時間內沒有接收到consumer訊息確認消費的響應結果,會將同一條訊息再次投遞給consumer。rocketmq採用ack機制保證訊息的消費成功,所以consumer可能會多次收到同一條訊息,需要consumer的業務方做好冪等防護。

  從使用者的角度來看,consumer分為兩種方式來獲取資訊。一種是推模式(push consume),推模式看起來像是brokerServer將訊息推給了consumer;另一種是拉模式(pull consume),拉模式看起來像是consumer主動的去brokerServer拉取訊息(實際上,推模式是基於拉模式實現的)。

3. BrokerServer

  brokerServer負責訊息的接收,儲存和分發,是rocketmq最核心,最重量級的組成部分。

  為實現高可用和高吞吐,brokerServer通常採用叢集部署,共同對外提供服務。

4. NameServer

   nameServer負責提供路由元資料。例如,brokerServer通常是叢集部署的,其拓撲結構會經常的發生變化。如果每次叢集中broker機器的上下線都需要通知所有的消費者、生產者,效率太低。

  因此,rocketmq引入了nameServer作為brokerServer路由資訊的維護者,broker的每次上下線都和nameServer通訊,由nameServer來維護broker的路由資訊,而producer和consumer通過訪問nameServer獲得對應broker的訪問地址後,再向對應的broker發起請求。nameServer解除了broker和客戶端的耦合依賴關係,大大提高了效率。

  在其它主流訊息佇列中也存在著類似的維護元資訊功能的元件,如zookeeper等。rocketmq的設計者認為zk的功能過於強大,殺雞焉用牛刀,通過一個精簡版的元資料服務nameServer,以減少對外部系統的耦合依賴,得以提供更可靠的服務。

  nameServer同樣能以叢集形式對外提供服務。但和zk叢集不同的是,叢集內的nameServer伺服器並不會互相通訊,而是保持相互獨立。

  

2.2 rocketmq基本概念模型

  介紹完rocketmq的組成部分之後,還需要再引入一些相關概念才能更好的理解rocketmq:  

1.topic 主題

  topic主題,代表一系列訊息的集合,任何訊息只能屬於一個topic主題,主題是rocketmq進行訊息釋出訂閱的最小單位。業務方可以通過建立並訂閱各式各樣的主題來滿足自身的業務要求。不同主題之間的訊息在邏輯上沒有關聯。

2.tag 標籤

  tag標籤,tag從屬於topic主題,主要用於對同一主題下的訊息進行進一步區分。標籤可以簡單的認為是二級主題,通過tag標籤功能,業務方可以方便的實現對各種二級主題的消費需求。

3.group 組

  group組,代表著同一類客戶端的集合。具體可分為消費者組(consumer group)和生產者組(producer group)兩種。消費者組和生產者組之間沒有任何關聯(即使組名一樣)。

消費者組:

  消費者組代表著同一型別的消費者叢集。同一消費者組內的消費者通常消費同樣的訊息且訊息消費邏輯一致。消費者組的概念使得consumer叢集在消費訊息時,rocketmq可以通過負載均衡來做到消費訊息時的高可用和容錯。消費者組的更多作用將會在後面的叢集/廣播消費模式中繼續講解。

生產者組:

  生產者組代表著同一型別的生產者叢集。一般來說,訊息的生產者在發出了訊息得到確認之後便完成了任務,似乎沒有必要為此抽象出生產者叢集的概念。

  前面說到,rocketmq具有傳送事務訊息的特性,傳送事務訊息簡單來說就是生產者先發送出一個半訊息(預訊息),然後執行本地的事務,在事務完成提交之後再跟著傳送一個事務確認訊息。半訊息和普通訊息的最大區別在於,半訊息在投遞給broker之後,broker不會馬上讓消費者進行消費,而是等待。只有當接收到生產者後續對應的的事務確認訊息後,預訊息和確認訊息合二為一,才將對應的事務訊息交給消費者去消費;而如果最終沒有接收到事務確認訊息,則會將訊息直接刪除不投遞給消費者,以達到類似事務回滾的效果。事務訊息對消費者來說是透明無感知的。

  可如果生產者在傳送了預訊息之後掛了怎麼辦?為解決這個問題,broker會在一定時間沒有收到確認訊息後,定時的回查生產者當前事務訊息的狀態,回查的範圍是整個生產者組中的某一個線上節點。這種情況下,生產者和消費者一樣,也構成了一個叢集監聽來自broker的回查。這樣,即使傳送訊息的生產者發生了故障,在一定條件下整個生產者叢集的事務訊息傳送功能依然可以正常運轉。

  通過生產者組的概念,rocketmq實現了事務訊息投遞的高可用。

4.message 訊息

  message訊息是rocketmq中傳遞訊息的主體,訊息具有全域性唯一的messageID屬性,使用者可以根據messageID查詢進行訊息的精確查詢。

  訊息的內容可以是不超過rocketmq限制的、二進位制的任意資料,rocketmq不會對訊息承載的資料內容做任何干預。

5. 叢集(Clustering)/廣播(Broadcasting)消費

叢集消費:

  對於任意一條被訂閱的訊息,同一消費者組下的節點只有一個節點對其進行消費;一個消費者組中的全部節點分攤所有訊息。

  

廣播消費:

  對於任意一條被訂閱的訊息,同一消費者組下的所有節點都會對其進行消費;一個消費者組中的全部節點都能接收到全量的訊息。

  

混合模式消費:

  實質上是前兩者的綜合。同一應用叢集構成一個消費者組,不同應用叢集之間構成多個不同的消費者組,但卻可以訂閱同一個topic/tag下的訊息。

  對於任意一條被訂閱的訊息,同一消費者組之間只會有一個節點對其進行消費,不同消費者組都會進行全量訊息的消費。

  

3.Rocketmq下載與安裝

  介紹了rocketmq的一些基本概念之後,下面進行rocketmq的下載和安裝,並進行基本的功能測試。簡單起見,nameServer,broker都以單機模式啟動。

  注意:示例中新版本的rocketmq要求jvm的最低版本是1.8。

3.1 從官網下載資源

  首先在rocketmq的官網可以找到下載資源,其中有已經編譯完成的二進位制資源(binary)和需要使用者自己編譯的原始碼資源(source)兩種。在這裡選擇下載已經編譯完成的,更容易上手的二進位制資源進行安裝。

   

3.2 配置rocketmq環境變數

  將下載好的資源解壓縮到任意目錄,可以看到如下資料夾和檔案,其中命令列的指令碼檔案都集中放在bin資料夾下。(這裡是windows環境下的操作,資源包中也包含了linux下同樣功能的shell指令碼檔案,操作並沒有明顯差異)

       

  由於指令碼檔案依賴一個叫做ROCKETMQ_HOME的環境變數,代指rocketmq安裝的主目錄,因此我們需要配置ROCKETMQ_HOME環境變數。

   

3.3 啟動nameServer

  開啟一個新的命令列視窗用於啟動nameServer,將命令列路徑指向bin檔案目錄,後續新開啟的命令列視窗需要做同樣的操作(也可以選擇配置path路徑,一勞永逸)。

  執行"mqnamesrv.cmd",看到如下圖的日誌資訊代表著nameServer已經啟動成功。保持nameServer視窗開啟,不要關閉。nameServer預設的啟動埠是9876。

  

   rocketmq 4.4.0版本的預設配置檔案記憶體設定的比較大,如果啟動時出現了jvm記憶體不足之類的錯誤,可以開啟runserver.cmd對其進行編輯,將預設的jvm記憶體分配引數設定的小一點。

3.4 啟動broker

  開啟一個新的命令列視窗,執行"mqbroker.cmd -n localhost:9876",用於啟動broker。前面提到,nameServer作為維護路由元資料的中心,broker會在啟動時會先在nameServer進行註冊,使得生產者和消費者能夠及時獲得broker相關的資訊。命令後面的-n localhost:9876引數就是用於指定對應nameServer的地址。

  當看到如下圖所示日誌資訊時,說明broker已經啟動完成。保持broker視窗開啟,不要關閉。

  

  和nameServer啟動一樣,如果出現了記憶體不足的問題,可以修改runbroker.cmd中的jvm啟動引數以符合要求。

  當nameServer和broker都啟動完成後,rocketmq的服務端就已經可以對外提供服務了。

3.5 啟動consumer和producer測試訊息收發功能

  rocketmq的開發人員在rocketmq中添加了簡單的demo訊息收發測試程式,我們可以通過tools.cmd呼叫來進行測試(和前面一樣,其啟動時的jvm引數直接在tools.cmd中修改即可)。

  首先開啟一個新的命令列視窗用於啟動consumer,先執行"set NAMESRV_ADDR=localhost:9876"設定命令列視窗級別的環境變數,然後執行"tools.cmd  org.apache.rocketmq.example.quickstart.Consumer",看到如下圖所示提示資訊時,代表consumer已經啟動成功。保持視窗開啟狀態,此時consumer正在監聽對應的訊息,等待消費。

  

  再開啟一個新的命令列視窗用於啟動producer,依然先執行"set NAMESRV_ADDR=localhost:9876",設定命令列視窗級別的環境變數,為生產者指定nameServer的地址。

  接著執行"tools.cmd  org.apache.rocketmq.example.quickstart.Producer",如無意外,會看到傳送訊息的刷屏日誌,producer在一瞬間就傳送了N條普通訊息(1000條);

  與此同時,consumer也接收到訊息,並在控制檯中打印出了訊息消費日誌。

  

  至此,rocketmq的安裝與基本功能的簡單測試宣告完成。

總結

  這是"rocketmq學習"系列的第一篇部落格,所以先以rockemq概念的介紹和安裝入手。後續的部落格內容將會有諸如rocketmq叢集部署、圖形化控制檯安裝等,並結合rocketmq的原始碼進一步理解rocketmq的工作原理。

  寫"rocketmq學習"系列部落格的主要目的還是為了鞏固並加深自己對rocketmq的理解。因為對於一些知識點只有在寫作的過程中才會發現對其瞭解的並不透徹,通過寫部落格可以很好的查漏補缺。

  如有理解不到位的地方,歡迎指正。