1、消息隊列介紹
消息隊列中間件是分布式系統(tǒng)中的重要組件,主要解決應(yīng)用耦合,異步消息,流量削鋒等問題,實現(xiàn)高性能,高可用,可伸縮和最終一致性的架構(gòu)
使用較多的消息隊列有ActiveMQ,RabbitMQ,Kafka,MetaMQ等
2、消息隊列應(yīng)用場景
2.1異步處理
場景說明:用戶注冊后,需要發(fā)注冊郵件和注冊短信。傳統(tǒng)的做法如下:
將注冊信息寫入數(shù)據(jù)庫成功后,發(fā)送注冊郵件,再發(fā)送注冊短信。以上三個任務(wù)全部完成后,返回給客戶端
引入消息隊列,將不是必須的業(yè)務(wù)邏輯,異步處理。改造后的架構(gòu)如下:
按照以上約定,用戶的響應(yīng)時間相當(dāng)于是注冊信息寫入數(shù)據(jù)庫的時間,也就是50毫秒。注冊郵件,發(fā)送短信寫入消息隊列后,直接返回,
因為寫入消息隊列的速度很快,基本可以忽略,因此用戶的響應(yīng)時間約為50毫秒。
2.2應(yīng)用解耦
場景說明:用戶下單后,訂單系統(tǒng)需要通知庫存系統(tǒng)。傳統(tǒng)的做法是,訂單系統(tǒng)調(diào)用庫存系統(tǒng)的接口。如下圖
傳統(tǒng)模式的缺點:
假如庫存系統(tǒng)無法訪問,則訂單減庫存將失敗,從而導(dǎo)致訂單失敗
訂單系統(tǒng)與庫存系統(tǒng)耦合
訂單系統(tǒng):用戶下單后,訂單系統(tǒng)完成持久化處理,將消息寫入消息隊列,返回用戶訂單下單成功
庫存系統(tǒng):訂閱下單的消息,采用拉/推的方式,獲取下單信息,庫存系統(tǒng)根據(jù)下單信息,進(jìn)行庫存操作
假如:在下單時庫存系統(tǒng)不能正常使用。也不影響正常下單,因為下單后,訂單系統(tǒng)寫入消息隊列就不再關(guān)心其他的后續(xù)操作了。實現(xiàn)訂單系統(tǒng)與庫存系統(tǒng)的應(yīng)用解耦
2.3流量削鋒
流量削鋒也是消息隊列中的常用場景,一般在秒殺或團(tuán)搶活動中使用廣泛
應(yīng)用場景:秒殺活動,一般會因為流量過大,導(dǎo)致流量暴增,應(yīng)用掛掉。為解決這個問題,一般需要在應(yīng)用前端加入消息隊列。
可以控制活動的人數(shù)
可以緩解短時間內(nèi)高流量壓垮應(yīng)用
用戶的請求,服務(wù)器接收后,首先寫入消息隊列。假如消息隊列長度超過最大數(shù)量,則直接拋棄用戶請求或跳轉(zhuǎn)到錯誤頁面
秒殺業(yè)務(wù)根據(jù)消息隊列中的請求信息,再做后續(xù)處理
3、JMS消息服務(wù)
講消息隊列就不得不提JMS 。JMS(Java Message Service)API是一個消息服務(wù)的標(biāo)準(zhǔn)/規(guī)范,允許應(yīng)用程序組件基于JavaEE平臺創(chuàng)建、發(fā)送、接收和讀取消息。它使分布式通信耦合度更低,消息服務(wù)更加可靠以及異步性。
3.1 消息模型
在JMS標(biāo)準(zhǔn)中,有兩種消息模型:
1、P2P(Point to Point)點對點模式
2、Publish/Subscribe(Pub/Sub) 發(fā)布訂閱模式
3.1.1 P2P模式
P2P模式包含三個角色:消息隊列(Queue),發(fā)送者(Sender),接收者(Receiver)。每個消息都被發(fā)送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留著消息,直到他們被消費或超時。
P2P的特點
每個消息只有一個消費者(Consumer)(即一旦被消費,消息就不再在消息隊列中)
發(fā)送者和接收者之間在時間上沒有依賴性,也就是說當(dāng)發(fā)送者發(fā)送了消息之后,不管接收者有沒有正在運行,它不會影響到消息被發(fā)送到隊列
接收者在成功接收消息之后需向隊列應(yīng)答成功
如果希望發(fā)送的每個消息都會被成功處理的話,那么需要P2P模式
3.1.2 Pub/sub模式
包含三個角色主題(Topic),發(fā)布者(Publisher),訂閱者(Subscriber) 多個發(fā)布者將消息發(fā)送到Topic,系統(tǒng)將這些消息傳遞給多個訂閱者。
Pub/Sub的特點
每個消息可以有多個消費者
發(fā)布者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須創(chuàng)建一個訂閱者之后,才能消費發(fā)布者的消息
為了消費消息,訂閱者必須保持運行的狀態(tài)
為了緩和這樣嚴(yán)格的時間相關(guān)性,JMS允許訂閱者創(chuàng)建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發(fā)布者的消息。
如果希望發(fā)送的消息可以不被做任何處理、或者只被一個消費者處理、或者可以被多個消費者處理的話,那么可以采用Pub/Sub模型。
3.2 JMS編程模型
(1) ConnectionFactory
創(chuàng)建Connection對象的工廠,針對兩種不同的jms消息模型,分別有QueueConnectionFactory和TopicConnectionFactory兩種??梢酝ㄟ^JNDI來查找ConnectionFactory對象。
(2) Destination
Destination的意思是消息生產(chǎn)者的消息發(fā)送目標(biāo)或者說消息消費者的消息來源。對于消息生產(chǎn)者來說,它的Destination是某個隊列(Queue)或某個主題(Topic);對于消息消費者來說,它的Destination也是某個隊列或主題(即消息來源)。
所以,Destination實際上就是兩種類型的對象:Queue、Topic可以通過JNDI來查找Destination。
(3) Connection
Connection表示在客戶端和JMS系統(tǒng)之間建立的鏈接(對TCP/IP socket的包裝)。Connection可以產(chǎn)生一個或多個Session。跟ConnectionFactory一樣,Connection也有兩種類型:QueueConnection和TopicConnection。
(4) Session
Session是操作消息的接口。可以通過session創(chuàng)建生產(chǎn)者、消費者、消息等。Session提供了事務(wù)的功能。當(dāng)需要使用session發(fā)送/接收多個消息時,可以將這些發(fā)送/接收動作放到一個事務(wù)中。同樣,也分QueueSession和TopicSession。
(5) 消息的生產(chǎn)者
消息生產(chǎn)者由Session創(chuàng)建,并用于將消息發(fā)送到Destination。同樣,消息生產(chǎn)者分兩種類型:QueueSender和TopicPublisher??梢哉{(diào)用消息生產(chǎn)者的方法(send或publish方法)發(fā)送消息。
(6) 消息消費者
消息消費者由Session創(chuàng)建,用于接收被發(fā)送到Destination的消息。兩種類型:QueueReceiver和TopicSubscriber。可分別通過session的createReceiver(Queue)或createSubscriber(Topic)來創(chuàng)建。當(dāng)然,也可以session的creatDurableSubscriber方法來創(chuàng)建持久化的訂閱者。
(7) MessageListener
消息監(jiān)聽器。如果注冊了消息監(jiān)聽器,一旦消息到達(dá),將自動調(diào)用監(jiān)聽器的onMessage方法。