更新時間:2021-07-28 17:02:21 來源:動力節點 瀏覽1290次
持久化消息和非持久化消息的發送策略
消息同步發送和異步發送
ActiveMQ支持同步、異步兩種發送模式將消息發送到broker上。同步發送過程中,發送者發送一條消息會阻塞直到broker反饋一個確認消息,表示消息已經被broker處理。這個機制提供了消息的安全性保障,但是由于是阻塞的操作,會影響到客戶端消息發送的性能。
異步發送的過程中,發送者不需要等待broker提供反饋,所以性能相對較高。但是可能會出現消息丟失的情況。所以使用異步發送的前提是在某些情況下允許出現數據丟失的情況。默認情況下,非持久化消息是異步發送的,持久化消息并且是在非事務模式下是同步發送的。但是在開啟事務的情況下,消息都是異步發送。由于異步發送的效率會比同步發送性能更高。所以在發送持久化消息的時候,盡量去開啟事務會話。
除了持久化消息和非持久化消息的同步和異步特性外,還可以通過以下幾種方式來設置異步發送
消息的發送原理分析圖解
ProducerWindowSize的含義
producer每發送一個消息,統計一下發送的字節數,當字節數達到ProducerWindowSize值時,需要等待broker的確認,才能繼續發送。代碼在:ActiveMQSession的1957行
主要用來約束在異步發送時producer端允許積壓的(尚未ACK)的消息的大小,且只對異步發送有意義。每次發送消息之后,都將會導致memoryUsage大小增加(+message.size),當broker返回producerAck時,memoryUsage尺寸減少(producerAck.size,此size表示先前發送消息的大小)。
Ø在brokerUrl中設置:"tcp://localhost:61616?jms.producerWindowSize=1048576",這種設置將會對所有的producer生效。
Ø在destinationUri中設置:"test-queue?producer.windowSize=1048576",此參數只會對使用此Destination實例的producer失效,將會覆蓋brokerUrl中的producerWindowSize值。
持久化消息和非持久化消息的存儲原理
正常情況下,非持久化消息是存儲在內存中的,持久化消息是存儲在文件中的。能夠存儲的最大消息數據在${ActiveMQ_HOME}/conf/activemq.xml文件中的systemUsage節點
SystemUsage配置設置了一些系統內存和硬盤容量
Ø從上面的配置我們需要get到一個結論,當非持久化消息堆積到一定程度的時候,也就是內存超過指定的設置閥值時,ActiveMQ會將內存中的非持久化消息寫入到臨時文件,以便騰出內存。但是它和持久化消息的區別是,重啟之后,持久化消息會從文件中恢復,非持久化的臨時文件會直接刪除
ActiveMQ消息持久性對于可靠消息傳遞來說是一種比較好的方法,即時發送者和接受者不是同時在線或者消息中心在發送者發送消息后宕機了,在消息中心重啟后仍然可以將消息發送出去。消息持久性的原理很簡單,就是在發送消息出去后,消息中心首先將消息存儲在本地文件、內存或者遠程數據庫,然后把消息發送給接受者,發送成功后再把消息從存儲中刪除,失敗則繼續嘗試。接下來我們來了解一下消息在broker上的持久化存儲實現方式
ActiveMQ支持多種不同的持久化方式,主要有以下幾種,不過,無論使用哪種持久化方式,消息的存儲邏輯都是一致的。
ØKahaDB存儲(默認存儲方式)ØJDBC存儲
ØMemory存儲
ØLevelDB存儲
ØJDBC With ActiveMQ Journal
KahaDB是目前默認的存儲方式,可用于任何場景,提高了性能和恢復能力。消息存儲使用一個事務日志和僅僅用一個索引文件來存儲它所有的地址。KahaDB是一個專門針對消息持久化的解決方案,它對典型的消息使用模式進行了優化。在Kaha中,數據被追加到data logs中。當不再需要log文件中的數據的時候,log文件會被丟棄。
KahaDB的配置方式
在data/kahadb這個目錄下,會生成四個文件
Ødb.data它是消息的索引文件,本質上是B-Tree(B樹),使用B-Tree作為索引指向db-*.log里面存儲的消息
Ødb.redo用來進行消息恢復
Ødb-*.log存儲消息內容。新的數據以APPEND的方式追加到日志文件末尾。屬于順序寫入,因此消息存儲是比較快的。默認是32M,達到閥值會自動遞增
Ølock文件鎖,表示當前獲得kahadb讀寫權限的broker
JDBC存儲
使用JDBC持久化方式,數據庫會創建3個表:activemq_msgs,activemq_acks和activemq_lock。
ACTIVEMQ_MSGS消息表,queue和topic都存在這個表中
ACTIVEMQ_ACKS存儲持久訂閱的信息和最后一個持久訂閱接收的消息ID
ACTIVEMQ_LOCKS鎖表,用來確保某一時刻,只能有一個ActiveMQ broker實例來訪問數據庫
JDBC存儲實踐
dataSource指定持久化數據庫的bean,createTablesOnStartup是否在啟動的時候創建數據表,默認值是true,這樣每次啟動都會去創建數據表了,一般是第一次啟動的時候設置為true,之后改成false
Mysql持久化Bean配置
添加Jar包依賴
消息消費流程圖
消息重發的情況
在正常情況下,有幾中情況會導致消息重新發送
Ø在事務性會話中,沒有調用session.commit確認消息或者調用
session.rollback方法回滾消息
Ø在非事務性會話中,ACK模式為CLIENT_ACKNOWLEDGE的情況下,沒有調用acknowledge或者調用了recover方法;
一個消息被redelivedred超過默認的最大重發次數(默認6次)時,消費端會給broker發送一個”poison ack”(ActiveMQMessageConsumer#dispatch:1460行),表示這個消息有毒,告訴broker不要再發了。這個時候broker會把這個消息放到DLQ(死信隊列)。
ActiveMQ采用消息推送方式,所以最適合的場景是默認消息都可在短時間內被消費。數據量越大,查找和消費消息就越慢,消息積壓程度與消息速度成反比。
1.吞吐量低。由于ActiveMQ需要建立索引,導致吞吐量下降。這是無法克服的缺點,只要使用完全符合JMS規范的消息中間件,就要接受這個級別的TPS。
2.無分片功能。這是一個功能缺失,JMS并沒有規定消息中間件的集群、分片機制。而由于ActiveMQ是偉企業級開發設計的消息中間件,初衷并不是為了處理海量消息和高并發請求。如果一臺服務器不能承受更多消息,則需要橫向拆分。ActiveMQ官方不提供分片機制,需要自己實現。
適用場景
對TPS要求比較低的系統,可以使用ActiveMQ來實現,一方面比較簡單,能夠快速上手開發,另一方面可控性也比較好,還有比較好的監控機制和界面
消息量巨大的場景。ActiveMQ不支持消息自動分片機制,如果消息量巨大,導致一臺服務器不能處理全部消息,就需要自己開發消息分片功能。
以上就是動力節點小編介紹的"ActiveMQ原理分析",希望對大家有幫助,想了解更多可查看ActiveMQ教程。動力節點在線學習教程,針對沒有任何Java基礎的讀者學習,讓你從入門到精通,主要介紹了一些Java基礎的核心知識,讓同學們更好更方便的學習和了解Java編程,感興趣的同學可以關注一下。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習