什麼是JMS MQ
全稱:Java MessageService 中文:Java 訊息服務。
JMS 是 Java 的一套 API 標準,最初的目的是為了使應用程式能夠訪問現有的 MOM 系 統(MOM 是 MessageOriented Middleware 的英文縮寫,指的是利用高效可靠的訊息傳遞機 制進行平臺無關的資料交流,並基於資料通訊來進行分散式系統的整合。) ;
後來被許多現有 的 MOM 供應商採用,並實現為 MOM 系統。【常見 MOM 系統包括 Apache 的 ActiveMQ、 阿里巴巴的 RocketMQ、IBM 的 MQSeries、Microsoft 的 MSMQ、BEA 的 RabbitMQ 等。 (並 非全部的 MOM 系統都遵循 JMS 規範)】
基於 JMS 實現的 MOM,又被稱為 JMSProvider。
“訊息”是在兩臺計算機間傳送的資料單位。訊息可以非常簡單,例如只包含文字字串; 也可以更復雜,可能包含嵌入物件。 訊息被髮送到佇列中。
“訊息佇列”是在訊息的傳輸過程中儲存訊息的容器。訊息佇列管 理器在將訊息從它的源中繼到它的目標時充當中間人。
佇列的主要目的是提供路由並保證消 息的傳遞;如果傳送訊息時接收者不可用,訊息佇列會保留訊息,直到可以成功地傳遞它。
訊息佇列的主要特點是非同步處理,主要目的是減少請求響應時間和解耦。所以主要的使 用場景就是將比較耗時而且不需要即時(同步)返回結果的操作作為訊息放入訊息佇列。同 時由於使用了訊息佇列,只要保證訊息格式不變,訊息的傳送方和接收方並不需要彼此聯絡, 也不需要受對方的影響,即解耦和。如: 跨系統的非同步通訊,所有需要非同步互動的地方都可以使用訊息佇列。就像我們除了打電 話(同步)以外,還需要發簡訊,發電子郵件(非同步)的通訊方式。 多個應用之間的耦合,由於訊息是平臺無關和語言無關的,而且語義上也不再是函式調 用,因此更適合作為多個應用之間的鬆耦合的介面。基於訊息佇列的耦合,不需要傳送方和 接收方同時線上。 在企業應用整合(EAI)中,檔案傳輸,共享資料庫,訊息佇列,遠端過程呼叫都可以 作為整合的方法。 應用內的同步變非同步,比如訂單處理,就可以由前端應用將訂單資訊放到佇列,後端應 用從佇列裡依次獲得訊息處理,高峰時的大量訂單可以積壓在佇列裡慢慢處理掉。由於同步 通常意味著阻塞,而大量執行緒的阻塞會降低計算機的效能。 訊息驅動的架構(EDA),系統分解為訊息佇列,和訊息製造者和訊息消費者,一個處 理流程可以根據需要拆成多個階段(Stage) ,階段之間用佇列連線起來,前一個階段處理的 結果放入佇列,後一個階段從佇列中獲取訊息繼續處理。 應用需要更靈活的耦合方式,如釋出訂閱,比如可以指定路由規則。 跨區域網,甚至跨城市的通訊,比如北京機房與廣州機房的應用程式的通訊。
訊息中介軟體應用場景
非同步通訊
有些業務不想也不需要立即處理訊息。訊息佇列提供了非同步處理機制,允許使用者把一個訊息放入佇列,但並不立即處理它。想向佇列中放入多少訊息就放多少,然後在需要的時候再去處理它們。
緩衝
在任何重要的系統中,都會有需要不同的處理時間的元素。訊息佇列通過一個緩衝層來幫助任務最高效率的執行,該緩衝有助於控制和優化資料流經過系統的速度。以調節系統響應時間。
解耦
降低工程間的強依賴程度,針對異構系統進行適配。在專案啟動之初來預測將來專案會碰到什麼需求,是極其困難的。通過訊息系統在處理過程中間插入了一個隱含的、基於資料的介面層,兩邊的處理過程都要實現這一介面,當應用發生變化時,可以獨立的擴充套件或修改兩邊的處理過程,只要確保它們遵守同樣的介面約束。
冗餘
有些情況下,處理資料的過程會失敗。除非資料被持久化,否則將造成丟失。訊息佇列把資料進行持久化直到它們已經被完全處理,通過這一方式規避了資料丟失風險。許多訊息佇列所採用的”插入-獲取-刪除”正規化中,在把一個訊息從佇列中刪除之前,需要你的處理系統明確的指出該訊息已經被處理完畢,從而確保你的資料被安全的儲存直到你使用完畢。
擴充套件性
因為訊息佇列解耦了你的處理過程,所以增大訊息入隊和處理的頻率是很容易的,只要另外增加處理過程即可。不需要改變程式碼、不需要調節引數。便於分散式擴容。
可恢復性
系統的一部分元件失效時,不會影響到整個系統。訊息佇列降低了程式間的耦合度,所以即使一個處理訊息的程式掛掉,加入佇列中的訊息仍然可以在系統恢復後被處理。
順序保證
在大多使用場景下,資料處理的順序都很重要。大部分訊息佇列本來就是排序的,並且能保證資料會按照特定的順序來處理。
過載保護
在訪問量劇增的情況下,應用仍然需要繼續發揮作用,但是這樣的突發流量無法提取預知;如果以為了能處理這類瞬間峰值訪問為標準來投入資源隨時待命無疑是巨大的浪費。使用訊息佇列能夠使關鍵元件頂住突發的訪問壓力,而不會因為突發的超負荷的請求而完全崩潰。
資料流處理
分散式系統產生的海量資料流,如:業務日誌、監控資料、使用者行為等,針對這些資料流進行實時或批量採集彙總,然後進行大資料分析是當前網際網路的必備技術,通過訊息佇列完成此類資料收集是最好的選擇。
常用訊息佇列(ActiveMQ、RabbitMQ、RocketMQ、Kafka)比較
特性MQ | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
生產者消費者模式 | 支援 | 支援 | 支援 | 支援 |
釋出訂閱模式 | 支援 | 支援 | 支援 | 支援 |
請求回應模式 | 支援 | 支援 | 不支援 | 不支援 |
Api完備性 | 高 | 高 | 高 | 高 |
多語言支援 | 支援 | 支援 | java | 支援 |
單機吞吐量 | 萬級 | 萬級 | 萬級 | 十萬級 |
訊息延遲 | 無 | 微秒級 | 毫秒級 | 毫秒級 |
可用性 | 高(主從) | 高(主從) | 非常高(分散式) | 非常高(分散式) |
訊息丟失 | 低 | 低 | 理論上不會丟失 | 理論上不會丟失 |
文件的完備性 | 高 | 高 | 高 | 高 |
提供快速入門 | 有 | 有 | 有 | 有 |
社群活躍度 | 高 | 高 | 有 | 高 |
商業支援 | 無 | 無 | 商業雲 | 商業雲 |
JMS中的一些角色
Broker
訊息伺服器,作為server提供訊息核心服務
provider
生產者
訊息生產者是由會話建立的一個物件,用於把訊息傳送到一個目的地。
Consumer
消費者
訊息消費者是由會話建立的一個物件,它用於接收傳送到目的地的訊息。訊息的消費可以採用以下兩種方法之一:
- 同步消費。通過呼叫消費者的receive方法從目的地中顯式提取訊息。receive方法可以一直阻塞到訊息到達。
- 非同步消費。客戶可以為消費者註冊一個訊息監聽器,以定義在訊息到達時所採取的動作。
p2p
基於點對點的訊息模型
訊息生產者生產訊息傳送到 queue 中,然後訊息消費者從 queue 中取出並且消費訊息。 訊息被消費以後,queue 中不再有儲存,所以訊息消費者不可能消費到已經被消費的消
息。
Queue 支援存在多個消費者,但是對一個訊息而言,只會有一個消費者可以消費、其它 的則不能消費此訊息了。 當消費者不存在時,訊息會一直儲存,直到有消費消費
pub/sub
基於訂閱/釋出的訊息模型
訊息生產者(釋出)將訊息釋出到 topic 中,同時有多個訊息消費者(訂閱)消費該消
息。
和點對點方式不同,釋出到 topic 的訊息會被所有訂閱者消費。 當生產者釋出訊息,不管是否有消費者。都不會儲存訊息 一定要先有訊息的消費者,後有訊息的生產者。
PTP 和 PUB/SUB 簡單對
1 | Topic | Queue |
---|---|---|
Publish Subscribe messaging 釋出 訂閱訊息 | Point-to-Point 點對點 | |
有無狀態 | topic 資料預設不落地,是無狀態的。 | Queue 資料預設會在 mq 服 務器上以檔案形式儲存,比如 Active MQ 一 般 保 存 在 $AMQ_HOME\data\kahadb 下 面。也可以配置成 DB 儲存。 |
完整性保障 | 並不保證 publisher 釋出的每條數 據,Subscriber 都能接受到。 | Queue 保證每條資料都能 被 receiver 接收。訊息不超時。 |
訊息是否會丟失 | 一般來說 publisher 釋出訊息到某 一個 topic 時,只有正在監聽該 topic 地址的 sub 能夠接收到訊息;如果沒 有 sub 在監聽,該 topic 就丟失了。 | Sender 發 送 消 息 到 目 標 Queue, receiver 可以非同步接收這 個 Queue 上的訊息。Queue 上的 訊息如果暫時沒有 receiver 來 取,也不會丟失。前提是訊息不 超時。 |
訊息釋出接 收策略 | 一對多的訊息釋出接收策略,監 聽同一個topic地址的多個sub都能收 到 publisher 傳送的訊息。Sub 接收完 通知 mq 伺服器 | 一對一的訊息釋出接收策 略,一個 sender 傳送的訊息,只 能有一個 receiver 接收。 receiver 接收完後,通知 mq 伺服器已接 收,mq 伺服器對 queue 裡的消 息採取刪除或其他操作。 |
Queue
佇列儲存,常用與點對點訊息模型
預設只能由唯一的一個消費者處理。一旦處理訊息刪除。
Topic
主題儲存,用於訂閱/釋出訊息模型
主題中的訊息,會傳送給所有的消費者同時處理。只有在訊息可以重複處 理的業務場景中可使用。
Queue/Topic都是 Destination 的子介面
ConnectionFactory
連線工廠,jms中用它建立連線
連線工廠是客戶用來建立連線的物件,例如ActiveMQ提供的ActiveMQConnectionFactory。
Connection
JMS Connection封裝了客戶與JMS提供者之間的一個虛擬的連線。
Destination
訊息的目的地
目的地是客戶用來指定它生產的訊息的目標和它消費的訊息的來源的物件。JMS1.0.2規範中定義了兩種訊息傳遞域:點對點(PTP)訊息傳遞域和釋出/訂閱訊息傳遞域。 點對點訊息傳遞域的特點如下:
- 每個訊息只能有一個消費者。
- 訊息的生產者和消費者之間沒有時間上的相關性。無論消費者在生產者傳送訊息的時候是否處於執行狀態,它都可以提取訊息。
釋出/訂閱訊息傳遞域的特點如下:
- 每個訊息可以有多個消費者。
- 生產者和消費者之間有時間上的相關性。
- 訂閱一個主題的消費者只能消費自它訂閱之後釋出的訊息。JMS規範允許客戶建立持久訂閱,這在一定程度上放鬆了時間上的相關性要求 。持久訂閱允許消費者消費它在未處於啟用狀態時傳送的訊息。
在點對點訊息傳遞域中,目的地被成為佇列(queue);在釋出/訂閱訊息傳遞域中,目的地被成為主題(topic)。
Session
JMS Session是生產和消費訊息的一個單執行緒上下文。會話用於建立訊息生產者(producer)、訊息消費者(consumer)和訊息(message)等。會話提供了一個事務性的上下文,在這個上下文中,一組傳送和接收被組合到了一個原子操作中。
JMS的訊息格式
JMS訊息由以下三部分組成的:
-
訊息頭。
每個訊息頭欄位都有相應的getter和setter方法。
-
訊息屬性。
如果需要除訊息頭欄位以外的值,那麼可以使用訊息屬性。
-
訊息體。
JMS定義的訊息型別有TextMessage、MapMessage、BytesMessage、StreamMessage和ObjectMessage。
TextMessage
文字訊息
MapMessage
k/v
BytesMessage
位元組流
StreamMessage
java原始的資料流
ObjectMessage
序列化的java物件
訊息可靠性機制
確認 JMS訊息
只有在被確認之後,才認為已經被成功地消費了。
訊息的成功消費通常包含三個階段:客戶接收訊息、客戶處理訊息和訊息被確認。
在事務性會話中,當一個事務被提交的時候,確認自動發生。
在非事務性會話中,訊息何時被確認取決於建立會話時的應答模式(acknowledgement mode)。該引數有以下三個可選值:
- Session.AUTO_ACKNOWLEDGE。當客戶成功的從receive方法返回的時候,或者從MessageListener.onMessage方法成功返回的時候,會話自動確認客戶收到的訊息。
- Session.CLIENT_ACKNOWLEDGE。客戶通過訊息的acknowledge方法確認訊息。需要注意的是,在這種模式中,確認是在會話層上進行:確認一個被消費的訊息將自動確認所有已被會話消費的訊息。例如,如果一個訊息消費者消費了10個訊息,然後確認第5個訊息,那麼所有10個訊息都被確認。
- Session.DUPS_ACKNOWLEDGE。該選擇只是會話遲鈍的確認訊息的提交。如果JMS Provider失敗,那麼可能會導致一些重複的訊息。如果是重複的訊息,那麼JMS Provider必須把訊息頭的JMSRedelivered欄位設定為true。
永續性
JMS 支援以下兩種訊息提交模式:
- PERSISTENT。指示JMS Provider持久儲存訊息,以保證訊息不會因為JMS Provider的失敗而丟失。
- NON_PERSISTENT。不要求JMS Provider持久儲存訊息。
優先順序
可以使用訊息優先順序來指示JMS Provider首先提交緊急的訊息。優先順序分10個級別,從0(最低)到9(最高)。如果不指定優先順序,預設級別是4。需要注意的是,JMS Provider並不一定保證按照優先順序的順序提交訊息。
訊息過期
可以設定訊息在一定時間後過期,預設是永不過期。
臨時目的地
可以通過會話上的createTemporaryQueue方法和createTemporaryTopic方法來建立臨時目的地。它們的存在時間只限於建立它們的連線所保持的時間。只有建立該臨時目的地的連線上的訊息消費者才能夠從臨時目的地中提取訊息。
持久訂閱
首先訊息生產者必須使用PERSISTENT提交訊息。客戶可以通過會話上的createDurableSubscriber方法來建立一個持久訂閱,該方法的第一個引數必須是一個topic,第二個引數是訂閱的名稱。 JMS Provider會儲存釋出到持久訂閱對應的topic上的訊息。如果最初建立持久訂閱的客戶或者任何其它客戶使用相同的連線工廠和連線的客戶ID、相同的主題和相同的訂閱名再次呼叫會話上的createDurableSubscriber方法,那麼該持久訂閱就會被啟用。JMS Provider會象客戶傳送客戶處於非啟用狀態時所釋出的訊息。 持久訂閱在某個時刻只能有一個啟用的訂閱者。持久訂閱在建立之後會一直保留,直到應用程式呼叫會話上的unsubscribe方法。
本地事務
在一個JMS客戶端,可以使用本地事務來組合訊息的傳送和接收。JMS Session介面提供了commit和rollback方法。事務提交意味著生產的所有訊息被髮送,消費的所有訊息被確認;事務回滾意味著生產的所有訊息被銷燬,消費的所有訊息被恢復並重新提交,除非它們已經過期。 事務性的會話總是牽涉到事務處理中,commit或rollback方法一旦被呼叫,一個事務就結束了,而另一個事務被開始。關閉事務性會話將回滾其中的事務。 需要注意的是,如果使用請求/回覆機制,即傳送一個訊息,同時希望在同一個事務中等待接收該訊息的回覆,那麼程式將被掛起,因為知道事務提交,傳送操作才會真正執行。 需要注意的還有一個,訊息的生產和消費不能包含在同一個事務中。
ActiveMQ
官方網站
Broker
ActiveMQ 5.0 的二進位制釋出包中bin目錄中包含一個名為activemq的指令碼,直接執行這個指令碼就可以啟動一個broker。 此外也可以通過Broker Configuration URI或Broker XBean URI對broker進行配置,以下是一些命令列引數的例子:
Example | Description |
---|---|
activemq | Runs a broker using the default 'xbean:activemq.xml' as the broker configuration file. |
activemq xbean:myconfig.xml | Runs a broker using the file myconfig.xml as the broker configuration file that is located in the classpath. |
activemq xbean:file:./conf/broker1.xml | Runs a broker using the file broker1.xml as the broker configuration file that is located in the relative file path ./conf/broker1.xml |
activemq xbean:file:C:/ActiveMQ/conf/broker2.xml | Runs a broker using the file broker2.xml as the broker configuration file that is located in the absolute file path C:/ActiveMQ/conf/broker2.xml |
activemq broker:(tcp://localhost:61616, tcp://localhost:5000)?useJmx=true | Runs a broker with two transport connectors and JMX enabled. |
activemq broker:(tcp://localhost:61616, network:tcp://localhost:5000)?persistent=false | Runs a broker with 1 transport connector and 1 network connector with persistence disabled. |
儲存
KahaDB儲存
KahaDB是預設的持久化策略,所有訊息順序新增到一個日誌檔案中,同時另外有一個索引檔案記錄指向這些日誌的儲存地址,還有一個事務日誌用於訊息回覆操作。是一個專門針對訊息持久化的解決方案,它對典型的訊息使用模式進行了優化。
在data/kahadb這個目錄下,會生成四個檔案,來完成訊息持久化
1.db.data 它是訊息的索引檔案,本質上是B-Tree(B樹),使用B-Tree作為索引指向db-*.log裡面儲存的訊息
2.db.redo 用來進行訊息恢復 *
3.db-.log 儲存訊息內容。新的資料以APPEND的方式追加到日誌檔案末尾。屬於順序寫入,因此訊息儲存是比較 快的。預設是32M,達到閥值會自動遞增
4.lock檔案 鎖,寫入當前獲得kahadb讀寫許可權的broker ,用於在叢集環境下的競爭處理
<persistenceAdapter> <!--directory:儲存資料的目錄;journalMaxFileLength:儲存訊息的檔案大小 --> <kahaDBdirectory="${activemq.data}/kahadb"journalMaxFileLength="16mb"/> </persistenceAdapter>
特性:
1、日誌形式儲存訊息;
2、訊息索引以 B-Tree 結構儲存,可以快速更新;
3、 完全支援 JMS 事務;
4、支援多種恢復機制kahadb 可以限制每個資料檔案的大小。不代表總計資料容量。
AMQ 方式
只適用於 5.3 版本之前。 AMQ 也是一個檔案型資料庫,訊息資訊最終是儲存在檔案中。記憶體中也會有快取資料。
<persistenceAdapter> <!--directory:儲存資料的目錄 ;maxFileLength:儲存訊息的檔案大小 --> <amqPersistenceAdapterdirectory="${activemq.data}/amq"maxFileLength="32mb"/> </persistenceAdapter>
效能高於 JDBC,寫入訊息時,會將訊息寫入日誌檔案,由於是順序追加寫,效能很高。
為了提升效能,建立訊息主鍵索引,並且提供快取機制,進一步提升效能。
每個日誌檔案的 大小都是有限制的(預設 32m,可自行配置) 。
當超過這個大小,系統會重新建立一個檔案。
當所有的訊息都消費完成,系統會刪除這 個檔案或者歸檔。
主要的缺點是 AMQ Message 會為每一個 Destination 建立一個索引,如果使用了大量的 Queue,索引檔案的大小會佔用很多磁碟空間。
而且由於索引巨大,一旦 Broker(ActiveMQ 應用例項)崩潰,重建索引的速度會非常 慢。
雖然 AMQ 效能略高於 Kaha DB 方式,但是由於其重建索引時間過長,而且索引檔案 佔用磁碟空間過大,所以已經不推薦使用。
JDBC儲存
使用JDBC持久化方式,資料庫預設會建立3個表,每個表的作用如下:
activemq_msgs:queue和topic的訊息都存在這個表中
activemq_acks:儲存持久訂閱的資訊和最後一個持久訂閱接收的訊息ID
activemq_lock:跟kahadb的lock檔案類似,確保資料庫在某一時刻只有一個broker在訪問
ActiveMQ 將資料持久化到資料庫中。
不指定具體的資料庫。 可以使用任意的資料庫 中。
本環節中使用 MySQL 資料庫。 下述檔案為 activemq.xml 配置檔案部分內容。
首先定義一個 mysql-ds 的 MySQL 資料來源,然後在 persistenceAdapter 節點中配置 jdbcPersistenceAdapter 並且引用剛才定義的資料來源。
dataSource 指定持久化資料庫的 bean,createTablesOnStartup 是否在啟動的時候建立數 據表,預設值是 true,這樣每次啟動都會去建立資料表了,一般是第一次啟動的時候設定為 true,之後改成 false。
Beans中新增
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
<property name="username" value="activemq"/>
<property name="password" value="activemq"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
修改persistenceAdapter
<persistenceAdapter>
<!-- <kahaDB directory="${activemq.data}/kahadb"/> -->
<jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="true" />
</persistenceAdapter>
依賴jar包
commons-dbcp commons-pool mysql-connector-java
表欄位解釋
activemq_acks:用於儲存訂閱關係。如果是持久化Topic,訂閱者和伺服器的訂閱關係在這個表儲存。
主要的資料庫欄位如下:
container:訊息的destination
sub_dest:如果是使用static叢集,這個欄位會有叢集其他系統的資訊
client_id:每個訂閱者都必須有一個唯一的客戶端id用以區分
sub_name:訂閱者名稱
selector:選擇器,可以選擇只消費滿足條件的訊息。條件可以用自定義屬性實現,可支援多屬性and和or操作
last_acked_id:記錄消費過的訊息的id。
2:activemq_lock:在叢集環境中才有用,只有一個Broker可以獲得訊息,稱為Master Broker,其他的只能作為備份等待Master Broker不可用,才可能成為下一個Master Broker。這個表用於記錄哪個Broker是當前的Master Broker。
3:activemq_msgs:用於儲存訊息,Queue和Topic都儲存在這個表中。
主要的資料庫欄位如下:
id:自增的資料庫主鍵
container:訊息的destination
msgid_prod:訊息傳送者客戶端的主鍵
msg_seq:是傳送訊息的順序,msgid_prod+msg_seq可以組成jms的messageid
expiration:訊息的過期時間,儲存的是從1970-01-01到現在的毫秒數
msg:訊息本體的java序列化物件的二進位制資料
priority:優先順序,從0-9,數值越大優先順序越高
xid:用於儲存訂閱關係。如果是持久化topic,訂閱者和伺服器的訂閱關係在這個表儲存。
LevelDB儲存
LevelDB持久化效能高於KahaDB,雖然目前預設的持久化方式仍然是KahaDB。並且,在ActiveMQ 5.9版本提供 了基於LevelDB和Zookeeper的資料複製方式,用於Master-slave方式的首選資料複製方案。 但是在ActiveMQ官網對LevelDB的表述:LevelDB官方建議使用以及不再支援,推薦使用的是KahaDB
Memory 訊息儲存
顧名思義,基於記憶體的訊息儲存,就是訊息儲存在記憶體中。persistent=”false”,表示不設定持 久化儲存,直接儲存到記憶體中
在broker標籤處設定。
JDBC Message store with ActiveMQ Journal
這種方式克服了JDBC Store的不足,JDBC儲存每次訊息過來,都需要去寫庫和讀庫。 ActiveMQ Journal,使用延遲儲存資料到資料庫,當訊息來到時先快取到檔案中,延遲後才寫到資料庫中。
當消費者的消費速度能夠及時跟上生產者訊息的生產速度時,journal檔案能夠大大減少需要寫入到DB中的訊息。 舉個例子,生產者生產了1000條訊息,這1000條訊息會儲存到journal檔案,如果消費者的消費速度很快的情況 下,在journal檔案還沒有同步到DB之前,消費者已經消費了90%的以上的訊息,那麼這個時候只需要同步剩餘的 10%的訊息到DB。 如果消費者的消費速度很慢,這個時候journal檔案可以使訊息以批量方式寫到DB。
協議
完整支援的協議
http://activemq.apache.org/configuring-version-5-transports.html
ActiveMQ支援的client-broker通訊協議有:TCP、NIO、UDP、SSL、Http(s)、VM。
Transmission Control Protocol (TCP)
1:這是預設的Broker配置,TCP的Client監聽埠是61616。
2:在網路傳輸資料前,必須要序列化資料,訊息是通過一個叫wire protocol的來序列化成位元組流。預設情況下,ActiveMQ把wire protocol叫做OpenWire,它的目的是促使網路上的效率和資料快速互動。
3:TCP連線的URI形式:tcp://hostname:port?key=value&key=value,加粗部分是必須的
4:TCP傳輸的優點:
(1)TCP協議傳輸可靠性高,穩定性強
(2)高效性:位元組流方式傳遞,效率很高
(3)有效性、可用性:應用廣泛,支援任何平臺
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
New I/O API Protocol(NIO)
1:NIO協議和TCP協議類似,但NIO更側重於底層的訪問操作。它允許開發人員對同一資源可有更多的client呼叫和服務端有更多的負載。
2:適合使用NIO協議的場景:
(1)可能有大量的Client去連結到Broker上一般情況下,大量的Client去連結Broker是被作業系統的執行緒數所限制的。因此,NIO的實現比TCP需要更少的執行緒去執行,所以建議使用NIO協議
(2)可能對於Broker有一個很遲鈍的網路傳輸NIO比TCP提供更好的效能
3:NIO連線的URI形式:nio://hostname:port?key=value
4:Transport Connector配置示例:
<transportConnectors>
<transportConnector
name="tcp"
uri="tcp://localhost:61616?trace=true" />
<transportConnector
name="nio"
uri="nio://localhost:61618?trace=true" />
</transportConnectors>
上面的配置,示範了一個TCP協議監聽61616埠,一個NIO協議監聽61618埠
User Datagram Protocol(UDP)
1:UDP和TCP的區別
(1)TCP是一個原始流的傳遞協議,意味著資料包是有保證的,換句話說,資料包是不會被複制和丟失的。UDP,另一方面,它是不會保證資料包的傳遞的
(2)TCP也是一個穩定可靠的資料包傳遞協議,意味著資料在傳遞的過程中不會被丟失。這樣確保了在傳送和接收之間能夠可靠的傳遞。相反,UDP僅僅是一個連結協議,所以它沒有可靠性之說
2:從上面可以得出:TCP是被用在穩定可靠的場景中使用的;UDP通常用在快速資料傳遞和不怕資料丟失的場景中,還有ActiveMQ通過防火牆時,只能用UDP
3:UDP連線的URI形式:udp://hostname:port?key=value
4:Transport Connector配置示例:
<transportConnectors>
<transportConnector
name="udp"
uri="udp://localhost:61618?trace=true" />
</transportConnectors>
Secure Sockets Layer Protocol (SSL)
1:連線的URI形式:ssl://hostname:port?key=value
2:Transport Connector配置示例:
<transportConnectors>
<transportConnector name="ssl" uri="ssl://localhost:61617?trace=true"/>
</transportConnectors>
Hypertext Transfer Protocol (HTTP/HTTPS)
1:像web和email等服務需要通過防火牆來訪問的,Http可以使用這種場合
2:連線的URI形式:http://hostname:port?key=value或者https://hostname:port?key=value
3:Transport Connector配置示例:
<transportConnectors>
<transportConnector name="http" uri="http://localhost:8080?trace=true" />
</transportConnectors>
VM Protocol(VM)
1、VM transport允許在VM內部通訊,從而避免了網路傳輸的開銷。這時候採用的連 接不是socket連線,而是直接的方法呼叫。
2、第一個建立VM連線的客戶會啟動一個embed VM broker,接下來所有使用相同的 broker name的VM連線都會使用這個broker。當這個broker上所有的連線都關閉 的時候,這個broker也會自動關閉。
3、連線的URI形式:vm://brokerName?key=value
4、Java中嵌入的方式: vm:broker:(tcp://localhost:6000)?brokerName=embeddedbroker&persistent=fal se , 定義了一個嵌入的broker名稱為embededbroker以及配置了一個 tcptransprotconnector在監聽埠6000上
5、使用一個載入一個配置檔案來啟動broker vm://localhost?brokerConfig=xbean:activemq.xml
HelloWorld
下載
安裝啟動
解壓後直接執行
bin/win64/activemq.bat
web控制檯
通過8161埠訪問
修改訪問埠
修改 ActiveMQ 配置檔案:/usr/local/activemq/conf/jetty.xml
jettyport節點
配置檔案修改完畢,儲存並重新啟動 ActiveMQ 服務。
開發
maven座標
<!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-all -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.11</version>
</dependency>
Sender
package com.mashibing.activemq01;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Sender {
public static void main(String[] args) throws Exception {
// 1. 建立工廠物件,
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnectionFactory.DEFAULT_USER,
ActiveMQConnectionFactory.DEFAULT_PASSWORD,
"tcp://localhost:61616"
);
//2 從工廠裡拿一個連線
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 從連線中獲取Session(會話)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 從會話中獲取目的地(Destination)消費者會從這個目的地取訊息
Queue queue = session.createQueue("f");
//從會話中建立訊息提供者
MessageProducer producer = session.createProducer(queue);
//從會話中建立文字訊息(也可以建立其它型別的訊息體)
for (int i = 0; i < 100; i++) {
TextMessage message = session.createTextMessage("msg: " + i);
// 通過訊息提供者傳送訊息到ActiveMQ
Thread.sleep(1000);
producer.send(message);
}
// 關閉連線
connection.close();
System.out.println("exit");
}
}
Receiver
package com.mashibing.activemq01;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Receiver {
public static void main(String[] args) throws Exception {
// 1. 建立工廠物件,
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnectionFactory.DEFAULT_USER,
ActiveMQConnectionFactory.DEFAULT_PASSWORD,
"tcp://localhost:61616"
);
//2 從工廠裡拿一個連線
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 從連線中獲取Session(會話)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 從會話中獲取目的地(Destination)消費者會從這個目的地取訊息
Queue queue = session.createQueue("f");
//從會話中建立訊息提供者
MessageConsumer consumer = session.createConsumer(queue);
//從會話中建立文字訊息(也可以建立其它型別的訊息體)
while (true) {
TextMessage receive = (TextMessage)consumer.receive();
System.out.println("TextMessage:" + receive.getText());
}
}
}
Active MQ的安全機制
web控制檯安全
# username: password [,rolename ...]
admin: admin, admin
user: user, user
yiming: 123, user
使用者名稱:密碼,角色
注意: 配置需重啟ActiveMQ才會生效。
訊息安全機制
修改 activemq.xml
在123行 節點中新增
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="admin" password="admin" groups="admins,publishers,consumers"/>
<authenticationUser username="publisher" password="publisher" groups="publishers,consumers"/>
<authenticationUser username="consumer" password="consumer" groups="consumers"/>
<authenticationUser username="guest" password="guest" groups="guests"/>
</users>
</simpleAuthenticationPlugin>
</plugins>