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