分散式訊息中介軟體-ActiveMQ
本章知識點:
什麼是訊息中介軟體 訊息中介軟體能做什麼 AciiveMQ簡介 從JMS規範來了解ActiveMQ JMS定義 JMS體系結構 訊息傳遞域 點對點訊息傳遞域 釋出訂閱訊息傳遞域 訊息結構組成 屬性 JMS API定義了5種訊息體格式 持久訂閱 JMS訊息的可靠性機制 JMS的事務性會話和非事務性會話 訊息的持久化和非持久化儲存 Broker是什麼 怎麼保證冪等性 P2P模型和PUB/SUB模型總結
什麼是訊息中介軟體?
可靠訊息機制進行平臺無關的資料傳輸
訊息中介軟體能做什麼?
比如電商平臺註冊功能來分析:使用者註冊一個服務,不單單是insert一條資料到資料庫就完事了,還需要傳送啟用郵箱,傳送新人紅包或者積分,傳送營銷簡訊等一系列操作,都需要耗時1s,那麼整個註冊過程就需要耗時4s才能響應給使用者。
可以對這些相對獨立操作(子域)實現非同步化執行,類似多執行緒並行處理概念。
多執行緒可以實現非同步化,只是訊息持久化、訊息重發這些條件,多執行緒並不能滿足。
訊息佇列就很好地滿足這些條件,實現非同步,解耦,削峰。
在秒殺地業務場景,流量非常大,通過訊息佇列可以很好地解決流量削峰問題。
秒殺描述:
使用者提交過來地請求,先寫入訊息佇列,訊息佇列是有長度地,如果訊息佇列的長度超過指定長度,直接拋棄。
秒殺的具體核心處理業務,接收訊息佇列中訊息進行處理,這裡的訊息處理能力取決於消費端本身的吞吐量。
還有在弱一致性事務模型中,可以採用分散式訊息佇列來實現最大能力通知來實現資料最終一致性。
AciiveMQ簡介:
基於JMS規範,高可用,高效能,可伸縮面向訊息服務的系統。
ActiveMQ特性:
- 多語言和協議編寫客戶端
- 對spring的支援
- 完全支援jms1.1和j2ee1.4規範
從JMS規範來了解ActiveMQ
JMS定義:
Java訊息服務(jms)是面向訊息中介軟體的API,在兩個應用程式之間,或者分散式系統中傳送訊息、非同步通訊。
JMS體系結構:
訊息傳遞域:
JMS規範中定義了兩種訊息傳遞域:點對點訊息傳遞域和釋出/訂閱 訊息傳遞域。
類似qq聊天的時候,在群裡面發訊息(釋出/訂閱)和給群裡單獨一個同學發訊息(點對點)。
點對點訊息傳遞域:
- 每個訊息只能有一個消費者
- 訊息的生產者和消費者之間沒有時間上的相關性,實現非同步消費。
釋出訂閱訊息傳遞域:
- 每個訊息可以有多個消費者
- 生產者和消費者之間有時間上的相關性,訂閱一個主題的消費者只能消費自它訂閱之後釋出的訊息。
- JMS規範允許客戶建立持久訂閱,可以在一定程度上降低時間上的相關性要求。
- 持久訂閱允許消費者消費它在未處於啟用狀態時傳送的訊息。
訊息結構組成:
JMS訊息由訊息頭、屬性、訊息體組成。
訊息頭(Header)-訊息頭包含訊息的識別資訊和路由資訊。
訊息頭的屬性:
- JMSDestination:訊息傳送的目的地,queue或者topic。
- JMSDeliveryMode:傳送模式。持久模式和非持久模式。
- JMSPriority:訊息優先順序(優先順序分為10個級別,0-9(遞增),如果不設定優先順序,預設級別是4)
- JMSMessageID:唯一識別每個訊息的id
屬性:
按照型別可以分為應用設定屬性,標準屬性和訊息中介軟體定義的屬性。
- 應用程式設定和新增的屬性,比如Message.setStringProperty("key","value");消費端接收方式:Enumeration em=message.getPropertyNames()。
- JMS定義的屬性
- JMSprovider特定的屬性
JMS API定義了5種訊息體格式(Text,Map,Byte,Stream,Object),可以使用不同形式傳送接收資料,並可相容現有的訊息格式:比如
- TextMessage:String物件
- MapMessage:名/值對的集合,名為String物件,值型別可以是Java任何資料型別
- BytesMessage:位元組流
- StreamMessage:java中的輸入輸出流
- ObjectMessage:Java中的可序列化物件
- Message:沒有訊息體,只有訊息頭和屬性
持久訂閱:
比如QQ,我們退出QQ,但是下次登入的時候登入後還可以接受到離線訊息。
持久訂閱就是這樣的道理,持久訂閱有兩個特點:
- 持久訂閱者和非持久訂閱者針對的是釋出訂閱模型
- 當Broker傳送訊息給訂閱者時,如果訂閱者處於未啟用狀態:持久訂閱者可以收到訊息,而非持久訂閱者收不到訊息。
- 當然這種方式也有一定的影響:當持久訂閱者處於未啟用狀態時,Broker需要為持久訂閱者儲存訊息;如果持久訂閱者訂閱的訊息過多會溢位。
- 持久訂閱時,客戶端向JMS伺服器註冊一個自己身份的ID,當這個客戶端處於離線狀態時,JMS Provider會為這個ID儲存所有傳送到主題的訊息,當客戶端再次連線JMS Provider時,會根據自己的ID得到所有自己處於離線時傳送到主題的訊息。
- 這個身份ID在程式碼中的體現就是connection的ClientID,聊天裝置相當於clientID,qq號相當於訂閱者名稱,每個裝置只能一個qq號登入,就實現了連線和訂閱者。
JMS訊息的可靠性機制:
相當於我們寄出一個快遞出去,收件人沒有收到快遞,就認為這個包裹處於待簽收狀態,這樣才能保證包裹能夠安全達到收件人手裡。訊息中介軟體也是一樣。
訊息的消費通常包括3個階段:客戶端接收訊息、客戶端處理訊息、訊息被確認。
JMS的事務性會話和非事務性會話:
JMS Session介面提供了session.commit()和session.rollback()方法。
在事務狀態下發送操作,訊息並未正在投遞到中介軟體,而只有進行session.commit()操作之後,訊息才會傳送到中介軟體,再轉發到適當的消費者進行消費。如果是呼叫session.rollback()操作,則表明,當前事務期間內所傳送的訊息都取消掉。
通過在建立session的時候使用true or false來決定當前的會話是事務性還是非事務性。
connection.creatSession(Boolean.True,Session.AUTO_ACKNOWLEDGE);
在事務性會話中:
訊息的確認是自動進行,也就是通過session.commit()之後,完成訊息的簽收。
注意:必須保證傳送端和接受端都是事務性會話。
在非事務性會話中:
訊息何時被確認取決於建立會話時的應答模式(acknowledgement mode)
有三個選項:
- Session.AUTO_ACKNOWLEDGE:傳送端自動確認傳送的message到達MQ 的broker服務上。
- Session.CLIENT_ACKNOWLEDGE:接收端通過呼叫message.acknowledge方法確認訊息,會把之前消費的訊息放入快取佇列中,acknowledge確認時統一發送broker的服務上,只關心消費過的訊息。
- Session.DUPS_OK_ACKNOWLEDGE:訊息延遲確認。指定訊息提供者在訊息接收者沒有確認訊息重發訊息,這種模式不在乎接收者接收到重複的訊息,h好處在於空閒時,將之前提交的訊息一次性提交給對應broker服務。
訊息的持久化和非持久化儲存:
訊息的持久化儲存也是保證訊息的可靠性最重要的機制之一,也就是訊息傳送到Broker上以後,如果broker出現故障宕機了那麼儲存在broker上的訊息不應該丟失。
設定訊息持久化:
producer.setDeliveryMode(DeliveryMode.PERSIS.TENT)----持久化到磁碟或資料庫,會有資源浪費,效能開銷,當消費者處理返回ack,訊息會從磁碟刪除,多個步驟組成。
設定訊息非持久化:
producer.setDeliveryMode(DeliveryMode.NONPERSIS.TENT)----儲存在記憶體,mq掛了,訊息會丟失。
訊息的非持久化儲存:
訊息提供者會使用儲存轉發機制,先將訊息儲存到穩定介質中,等訊息傳送成功後再刪除,如果是jms.provider掛掉了,那麼這些未到達的訊息不會丟失;jms provider恢復正常後,會重新讀取這些資訊,並傳送給對應的消費者。
Broker是什麼:
訊息佇列核心,控制中心,負責訊息路由,儲存訂閱和連線資訊,訊息服務提供者。
怎麼保證冪等性:
網路延遲情況下,可能造成訊息重複消費,MQ本身無法解決冪等,需要在消費端判斷全域性id來解決訊息是否重複消費。
P2P模型和PUB/SUB模型總結:
P2P模型:
- 如果session關閉時,有一些訊息已經被收到,但是沒有被簽收,消費者下一次連線到相同佇列時,會接收。
- 如果使用者在receiver方法中設定了訊息的選擇條件(訊息過濾)。
- 如果是持久化訊息,訊息會被持久化儲存,直到訊息被簽收。
PUB/SUB模型:
- 持久化訂閱和非持久化訂閱。
- 在非持久化訂閱的前提下,不能重複恢復或者重新指派一個未簽收的訊息。
- 如果所有的訊息都要被簽收,需要使用持久訂閱。