天天看點

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

文章目錄

  • SpringBoot與消息服務
    • 為什麼要有消息中間件?
      • 例子1(異步通信):
      • 例子2(應用解耦):
      • 例子3(流量銷峰):
    • 消息服務規範
      • 概念
      • JMS
      • AMQP
      • Spring支援
    • RabbitMQ
      • 核心概念
      • 運作機制
        • Exchange:
          • DirectExchange
          • FanoutExchange
          • TopicExchange

SpringBoot與消息服務

為什麼要有消息中間件?

消息(Message)是指軟體對象之間進行互動作用和通訊利用的一種方式。中間件(Middleware)是處于作業系統和應用程式之間的軟體,也有人認為它應該屬于作業系統中的一部分。消息中間件則是将軟體與軟體之間的互動消息、互動方式進行存儲和管理的一種技術,也可以看做是一種容器。消息中間件關注于資料的發送和接收,利用高效可靠的異步消息傳遞機制內建分布式系統。

消息服務的應用場景有很多很多:系統解耦、異步、擴充、流量銷峰、日志處理、消息通信等等。。。通過幾個簡單例子了解一下消息服務的作用和好處:

例子1(異步通信):

使用者注冊成功,将注冊資訊寫入資料庫然後給使用者發送注冊郵件和發送注冊短信,串行方式:

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

注冊資訊持久化之後的發送注冊郵件和注冊短信可以使用多線程并發操作,并行方式:

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

但是,當注冊資訊寫入資料庫、發送短信和郵件之前就應該讓使用者完成注冊了。我們可以引入消息隊列,隻要将後序要用的資料寫入消息隊列就算注冊流程完畢了。發送郵件和發送短信可以通過異步讀取的方式從消息隊列中取出資料,然後完成相應的服務。

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

傳統方式的系統性能(并發量,吞吐量,響應時間)會有瓶頸。通過引入消息隊列,将不是必須的業務邏輯,異步處理,進而達到提高系統性能的目的。

例子2(應用解耦):

一個應用寫有訂單系統和庫存系統,我們下單然後去調用庫存系統的方法來檢索庫存,傳統做法:訂單系統去調用庫存系統對外提供的接口。但是傳統的做法存在缺點:

  1. 假如庫存系統無法通路,則訂單減庫存将失敗,進而導緻訂單失敗。
  2. 訂單系統與庫存系統耦合。

為了解決以上缺點,我們可以引入消息隊列,并将訂單系統和庫存系統抽取出來作為兩個獨立的服務:

  • 訂單系統:使用者下單後,訂單系統完成持久化處理,将消息寫入消息隊列,傳回使用者訂單下單成功。
  • 庫存系統:訂閱下單的消息,采用拉/推的方式,擷取下單資訊,庫存系統根據下單資訊,進行庫存操作。
系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

假如:在下單時庫存系統不能正常使用。也不影響正常下單,因為下單後,訂單系統寫入消息隊列就不再關心其他的後續操作了。實作訂單系統與庫存系統的應用解耦。至于怎麼保證兩個服務之間庫存量等資料一緻,暫時先不讨論。。。

例子3(流量銷峰):

流量削鋒也是消息隊列中的常用場景,一般在秒殺或團搶活動中使用廣泛。

應用場景:秒殺活動,一般會因為流量過大,導緻流量暴增,應用挂掉。為解決這個問題,一般需要加入消息隊列來控制使用者數量和緩解高流量的壓力。

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

使用者的請求,伺服器接收後,首先寫入消息隊列。假如消息隊列長度超過最大數量,則直接抛棄使用者請求并做出一定的響應操作。秒殺業務根據消息隊列中的請求資訊,再做後續處理。這隻是很籠統很模糊的說了一下,具體細節還有很多很多。。

消息服務規範

概念

消息服務中有兩個重要的概念:消息代理(MassageBroker)、目的地(destination)

當消息發送者發送消息以後,将由消息代理接管,消息代理保證消息傳遞到指定目的地。

消息隊列主要有兩種形式的目的地:

  1. 隊列(queue):點對點式消息通信(point-to-point),消息發送者發送消息,消息代理将其放入一個隊列中,消息接收者從隊列中擷取消息内容,消息讀取後被移出隊列,消息隻有唯一的發送者和接受者,但并不是說隻有一個接收者,也就是說A、B、C等等接收者都有資格去接受消息,但是一個消息最終隻能被一個接收者所接受。有點拗口,但是很好了解。。。
  2. 主題(topic):釋出(publish)/訂閱(subscribe)式消息通信,釋出者發送消息到主題,多個接收者(訂閱者)監聽(訂閱)這個主題,那麼當消息到達主題的時候這個主題所有的接收者(訂閱者)都會受到消息。

JMS

Java消息服務(Java Message Service)即JMS,是一個Java平台中關于面向消息中間件的api,用于在兩個應用程式之間或分布式系統中發送消息,進行異步通信。

基于JVM消息代理的規範,ActiveMQ、HornetMQ是JMS實作。

AMQP

進階消息隊列協定(advanced message queuing protocol)即AMQP,是一個提供統一消息服務的應用層标準協定,基于此協定的用戶端與消息中間件可傳遞消息,并且不受用戶端/中間件不同的産品、不同的開發語言等條件的限制。

也是一個消息代理的規範,相容JMS,RabbitMQ是AMQP的實作。

再偷一張JMS和AMQP對比圖:

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

Spring支援

  • spring-jms提供了對JMS的支援。
  • spring-rabbit提供了對AMQP的支援。
  • 需要ConnectionFactory的實作來連接配接消息代理。
  • 提供JmsTemplate、RabbitTemplate來發送消息。
  • @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上監聽消息代理釋出的消息。
  • @EnableJms、@EnableRabbit開啟支援。

SpringBoot自動配置:

  • JmsAutoConfiguration
  • RabbitAutoConfiguration

RabbitMQ

RabbitMQ是一個基于AMQP使用erlang開發的開源實作。

核心概念

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

**Message:消息,消息是不具名的,他有消息頭和消息體組成,消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對于其他消息的優先權)、delivery-mode(指出該消息可能需要持久性存儲)**等等。。

Publisher:消息的生産者,也是一個向交換器釋出消息的用戶端應用程式。

Exchange:交換器,用來接收生産者發送的消息并将這些消息路由給容器中的隊列,交換器有點像是網絡中的交換機,而容器中的隊列像是連接配接在交換機上的主機。Exchange有四種類型:direct(預設)、fanout、topic和headers,不同類型的Exchange轉發消息的政策有所差別。

Queue:消息隊列,用來儲存消息直到發送給消費者。它是消息的容器,也是消息的終點。一個消息可投入一個或者多個隊列。消息一直在隊列裡面,等待消費者連接配接到這個隊列将其取走。

Binding:綁定,用于消息隊列和交換器之間的關聯。一個綁定就是基于路由鍵将交換器和消息隊列連接配接起來的路由規則,是以可以将其了解成一個由綁定構成的路由表。Exchange和Queue的綁定可以是多對多的關系。

**Connection:**網絡連接配接,比如一個TCP連接配接。

**Channel:**信道,多路複用連接配接中的一條獨立的雙向資料流通道。信道是建立在真實的TCP連接配接内的虛拟連接配接,AMQP指令都是通過信道發出去的,不管是釋出消息、訂閱隊列還是接收消息,這些動作都是通過信道完成。因為對于作業系統來說建立和銷毀TCP都是非常昂貴的開銷,是以引入了信道的概念,以複用一條TCP連接配接。

**Consumer:**消息的消費者,表示一個從消息隊列中取得資訊的用戶端應用程式。

Virtual Host:虛拟主機,表示一批交換器、消息隊列和相關對象。虛拟主機是共享相同的身份認證和加密環境的獨立伺服器域。每個虛拟主機本質上就是一個mini版的RabbitMQ伺服器,擁有自己的隊列、交換器、綁定和權限機制。虛拟主機是AMQP概念的基礎,必須在連接配接時指定,RabbitMQ預設的虛拟主機是/。

**Broker:**表示消息隊列伺服器實體。

運作機制

AMQP中的消息路由過程和Java開發者熟悉的JMS存在一些差别,AMQP中增加了Exchange和Binding的角色,生産者把消息釋出到Exchange上,消息最終到達隊列并被消費者接收,而Binding決定交換器的消息應該發送到哪個隊列。

系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

Exchange:

分發消息時根據交換器類型的不同分發政策有差別,之前說過共有四種交換器類型:direct、fanout、topic、headers(很少用)。header比對AMQP消息的header而不是路由鍵,headers交換器和direct交換器完全一緻,但性能差很多,目前幾乎用不到了,是以着重學習另外三種類型:

DirectExchange
系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

消息中路由鍵(routing key)如果和Binding中的binding key一緻,交換器就将消息發送到對應的隊列中。路由鍵與隊列名必須完全比對,如果一個隊列綁定到交換器要求路由鍵為“dog”,則其轉發routing key标記為“dog”的消息,不會轉發“dog.puppy",也不轉發"dog.guard"等等。它是完全比對、單點傳播的模式,典型的點對點通信模型。

FanoutExchange
系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

每個發到fanout類型交換器的消息都會分到所有綁定的隊列上去。fanout交換器不處理路由鍵,隻是簡單的将隊列綁定到交換器上,每個發送到交換器的消息都會被轉發到與該交換器綁定的所有隊列上。很像子網廣播,每台子網内的主機都獲得了一份指派的消息。fanout類型轉發消息是最快的。這也是JMS裡面釋出/訂閱模型一個參考實作。

TopicExchange
系統學習-SpringBoot與消息服務(一)SpringBoot與消息服務

topic交換器通過模式比對配置設定消息的路由鍵屬性,将路由鍵和某個模式進行比對,此時隊列需要綁定到一個模式上。它将路由鍵和綁定建的字元串切分成單詞,這些單詞之間用點隔開。它同樣也會識别兩個通配符“#”和“*”,#比對0個或多個任意單詞,*比對一個任意單詞。

RabbitMq的安裝和測試就不記錄了,網上教程很多很詳細,各種問題大多也都有解決方案。

接下來另起新篇,記錄簡單的SpringBoot整合RabbitMQ!

繼續閱讀