(接上文《架構設計:系統間通訊(23)——提升ActiveMQ工做性能(中)》)java
前文已經講過,當ActiveMQ接收到PERSISTENT Message消息後就須要藉助持久化方案來完成PERSISTENT Message的存儲。這個介質能夠是磁盤文件系統、能夠是ActiveMQ的內置數據庫,還能夠是某種外部提供的關係型數據庫。本節筆者將向讀者講解三種ActiveMQ推薦的存儲方案的配置使用。mysql
如上圖2.1的步驟所示,全部PERSISTENT Message都要執行持久化存儲操做,持久化存儲操做方案的性能直接影響着整個MQ服務端的PERSISTENT Message吞吐性能。另外NON_PERSISTENT Message雖然不會進行持久化存儲,可是NON_PERSISTENT Message也不是永遠都只存在與內存區域。web
有的讀者會問,Topic模式的工做隊列在沒有任何活動訂閱者的狀況下也會對PERSISTENT Message進行持久化存儲嗎?固然會,由於Topic模式的工做隊列還要考慮「Durable Topic Subscribers」形式的訂閱者。即便沒有「Durable Topic Subscribers」形式的訂閱者,先存儲再標記的過程也不會改變(只是不必定真正進入物理磁盤)。算法
有的讀者還會問,在客戶端啓動事務的狀況下,若是沒有事務的commit操做,PERSISTENT Message也會進行持久化存儲嗎?固然仍是會,前文咱們已經講過沒有作事務的commit只是說這些事務中的消息不會進行確認操做,不會分發到某個指定的具體隊列中;可是只要使用了send方法,PERSISTENT Message就會被髮送到服務端,就會進行持久化存儲操做。spring
如上圖中被標示爲2.2的操做步驟所示,在ActiveMQ設置的持久化方案完成某條消息的持久化後,會在ActiveMQ服務節點的內部發出一個「完成」信號。這是爲了告訴ActiveMQ服務節點本身,是否能夠進行下一步操做。可是爲了加快ActiveMQ服務節點內部的處理效率,這個過程能夠設置爲「異步」。sql
那麼進行了持久化存儲的PERSISTENT Message何時被刪除呢?就如同以前咱們提到的同樣,ActiveMQ服務端只有在收到消費者端某一條消息或某一組消息的ACK標示後,纔會認爲消息被消費者端正確處理了。就是在這個時候,ActiveMQ會通知持久化方案,進行刪除這一條或者這一組消息的操做,並空閒出相應的存儲空間。如上圖被標示爲5.1的操做步驟所示。數據庫
在介紹ActiveMQ的存儲方案以前,首先須要明確的是ActiveMQ中的幾種「容量」描述:apache
...... # Initial Java Heap Size (in MB) wrapper.java.initmemory=100 # Maximum Java Heap Size (in MB) wrapper.java.maxmemory=512 ......
以上配置項設置JVM的初始內存大小爲100MB,設置JVM的最大內存大小爲512MB。若是您在更改後使用console參數啓動ActiveMQ,那麼會看到當前ActiveMQ的JVM設置發生了變化:網絡
<systemUsage>
<systemUsage>
<memoryUsage>
<memoryUsage percentOfJvmHeap="70" />
</memoryUsage>
<storeUsage>
<storeUsage limit="100 gb"/>
</storeUsage>
<tempUsage>
<tempUsage limit="50 gb"/>
</tempUsage>
</systemUsage>
</systemUsage>
systemUsage:該標記用於設置整個ActiveMQ節點在進程級別的各類「容量」的設置狀況。其中可設置的屬性包括:sendFailIfNoSpaceAfterTimeout,當ActiveMQ收到一條消息時,若是ActiveMQ這時已經沒有多餘「容量」了,那麼就會等待一段時間(這裏設置的毫秒數),若是超過這個等待時間ActiveMQ仍然沒有可用的容量,那麼就拒絕接收這條消息並在消息的發送端拋出javax.jms.ResourceAllocationException異常;sendFailIfNoSpace,當ActiveMQ收到一條消息時,若是ActiveMQ這時已經沒有多餘「容量」了,就直接拒絕這條消息(不用等待一段時間),並在消息的發送端拋出javax.jms.ResourceAllocationException異常。多線程
memoryUsage:該子標記設置整個ActiveMQ節點的「可用內存限制」。這個值不能超過上文中您設置的JVM maxmemory的值。其中的percentOfJvmHeap屬性表示使用「百分數值」進行設置,除了這個屬性之外,您還可使用limit屬性進行固定容量受權,例如:limit=」1000 mb」。這些內存容量將供全部隊列使用。
storeUsage:該標記設置整個ActiveMQ節點,用於存儲「持久化消息」的「可用磁盤空間」。該子標記的limit屬性必需要進行設置。在使用後續介紹的KahaDB方案或者LevelDB方案進行PERSISTENT Message持久化存儲時,這個storeUsage屬性都會起做用;可是若是使用數據庫存儲方案,這個屬性就不會起做用了。
tempUsage:在ActiveMQ 5.X+ 版本中,一旦ActiveMQ服務節點存儲的消息達到了memoryUsage的限制,NON_PERSISTENT Message就會被轉儲到 temp store區域。雖然咱們說過NON_PERSISTENT Message不進行持久化存儲,可是ActiveMQ爲了防止「數據洪峯」出現時NON_PERSISTENT Message大量堆積導致內存耗盡的狀況出現,仍是會將NON_PERSISTENT Message寫入到磁盤的臨時區域——temp store。這個子標記就是爲了設置這個temp store區域的「可用磁盤空間限制」。最後提醒各位讀者storeUsage和tempUsage並非「最大可用空間」,而是一個閥值。
說到ActiveMQ中持久化存儲方案的演化問題,若是您仔細閱讀ActiveMQ官方文檔中關於持久化部分的描述,您就不難發現ActiveMQ的開發團隊在針對持久化性能問題的優化上可謂與時俱進。這也符合一款健壯軟件的生命週期特徵:任何功能特性都在進行不斷累計完善:
從最初的AMQ Message Store方案,到ActiveMQ V4版本中推出的High performance journal(高性能事務支持)附件 ,而且同步推出了關於關係型數據庫的存儲方案。ActiveMQ 5.3版本中又推出了對KahaDB的支持(V5.4版本後稱爲ActiveMQ默認的持久化方案),後來ActiveMQ V5.8版本開始支持LevelDB,到如今,V5.9+版本提供了標準的Zookeeper+LevelDB集羣化方案。下面咱們重點介紹一下ActiveMQ中KahaDB、LevelDB和關係型數據庫這三種持久化存儲方案。而且會和讀者一塊兒,使用Zookeeper搭建LevelDB集羣存儲方案。
對於最初的AMQ Message Store方案,ActiveMQ官方已再也不推薦使用(實際上在筆者的實際工做中,也不會使用AMQ Message Store)。若是各位讀者想進行了解能夠自行搜索相關資料,這裏再也不進行介紹。
KahaDB is a file based persistence database that is local to the message broker that is using it. It has been optimised for fast persistence and is the the default storage mechanism from ActiveMQ 5.4 onwards. KahaDB uses less file descriptors and provides faster recovery than its predecessor, the AMQ Message Store.
以上引用自Apache ActiveMQ 官方對KahaDB的定義。首先KahaDB基於文件系統,其次KahaDB支持事務。在ActiveMQ V5.4版本及後續版本KahaDB都是ActiveMQ的默認持久化存儲方案。最後Apache ActiveMQ官方表示它用來替換以前的AMQ Message Store存儲方案。
KahaDB主要元素包括:一個內存Metadata Cache用來在內存中檢索消息的存儲位置、若干用於記錄消息內容的Data log文件、一個在磁盤上檢索消息存儲位置的Metadata Store、還有一個用於在系統異常關閉後恢復Btree結構的redo文件。以下圖所示(官網引用):
如下是KahaDB在磁盤文件上的現實展現。注意,可能您查看本身測試實例中所運行的KahaDB,看到的效果和本文中給出的效果不徹底一致。例如您的data log文件可能叫db-1.log,也有可能會多出一個db.free的文件,可是這些都不影響咱們對文件結構的分析:
[root@localhost KahaDB]# ll -h
總用量 29M
-rw-r--r--. 1 root root 32M 4月 7 04:53 db-3.log
-rw-r--r--. 1 root root 7.6M 4月 7 04:53 db.data
-rw-r--r--. 1 root root 2.8M 4月 7 04:53 db.redo
-rw-r--r--. 1 root root 8 4月 7 04:50 lock
db-3.log:這個文件就是咱們上文提到的Data log文件。一個KahaDB中,可能同時存在多個Data log文件,他們存儲了每一條持久化消息的真正內容。這些Data log文件統一採用db-*.log的格式進行命名,而且每一個Data log文件默認的大小都是32M(固然是能夠進行設置的)。當一個Data log文件中的全部消息所有被成功消息後,這個Data log文件會在Metadata Cache中被標記爲刪除,並在下個checkpoint週期進行刪除操做。
各位讀者可能已經注意到一個現象:爲何db-3.log的默認佔用大小就是32M,可是目錄顯示的「總用量」卻只有29M呢?在這個文件夾中,除了db-3.log文件自己,加上其餘幾個文件所佔用的大小,已經遠遠超過了32M!這是由於,爲了加快寫文件的性能,Data log文件採用順序寫的方式進行操做,爲了保證文件使用的扇區在物理上是連續的,因此Data log文件須要預佔這些扇區(這個和Hadoop中每個block大小都是固定的緣由類似)。雖然您看到Data log文件佔用的32M的磁盤空間,可是這些磁盤空間並無所有使用。另外,關於隨機讀寫和連續讀寫的巨大性能差別,我會在今年下半年新的「數據存儲專欄」中,進行詳細介紹。
爲了更快的找到某個具體消息在Data log文件中的具體位置。消息的位置索引採用BTree的結構被存儲在內存中,這個內存區域就是上文提到的Metadata Cache(大小也是能夠設置的)。要知道Mysql的Innodb 存儲引擎也是採用BTree結構構造索引結構(用了都說快哦~~)。因此通常狀況下,只要某個隊列有活動的消費者存在,消息的定位、讀取操做是能夠很快完成的。
內存中沒有被處理的消息索引會以必定的週期(或者必定的數量規模)爲依據,同步(checkpoint)到Metadata Store中,這就是咱們在上文中看到的「db.data」文件。固然db.redo文件也會被更新,以便在ActiveMQ服務節點在重啓後對Metadata Cache進行恢復。最後,消息同步(checkpoint)依據,能夠在ActiveMQ的主配置文件中進行設置。
因爲在ActiveMQ V5.4+的版本中,KahaDB是默認的持久化存儲方案。因此即便您不配置任何的KahaDB參數信息,ActiveMQ也會啓動KahaDB。這種狀況下,KahaDB文件所在位置是您的ActiveMQ安裝路徑下的/data/${broker.Name}/KahaDB子目錄。其中${broker.Name}表明這個ActiveMQ服務節點的名稱。
正式的生產環境仍是建議您在主配置文件中明確設置KahaDB的工做參數。以下所示:
......
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
......
</broker>
......
以上配置項設置使用kahaDB爲持久化存儲方法,而且設置kahaDB的工做目錄爲ActiveMQ安裝路勁下/data/kahadb目錄。若是您須要Data log文件默認的32M的大小,可使用journalMaxFileLength屬性進行設置,以下所示:
......
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb" journalMaxFileLength="64mb"/>
</persistenceAdapter>
......
</broker>
......
您還能夠設置爲:當Metadata Cache中和Metadata Store中不一樣的索引條數達到500條時,就進行checkpoint同步。以下所示:
......
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb" journalMaxFileLength="64mb" indexWriteBatchSize="500"/>
</persistenceAdapter>
......
</broker>
......
如下表格爲讀者示例了KahaDB中全部的配置選項和其含義(引用自網絡,加「*」部分是筆者認爲重要的配置選項):
property name | default value | Comments |
---|---|---|
*directory | activemq-data | 消息文件和日誌的存儲目錄 |
*indexWriteBatchSize | 1000 | 當Metadata cache區域和Metadata store區域不一樣的索引數量達到這個值後,Metadata cache將會發起checkpoint同步 |
*indexCacheSize | 10000 | 內存中,索引的頁大小。超過這個大小Metadata cache將會發起checkpoint同步 |
*enableIndexWriteAsync | false | 索引是否異步寫到消息文件中,將以不要設置爲true |
*journalMaxFileLength | 32mb | 一個消息文件的大小 |
*enableJournalDiskSyncs | true | 若是爲true,保證使用同步寫入的方式持久化消息到journal文件中 |
*cleanupInterval | 30000 | 清除(清除或歸檔)再也不使用的db-*.log文件的時間週期(毫秒)。 |
*checkpointInterval | 5000 | 寫入索引信息到metadata store中的時間週期(毫秒) |
ignoreMissingJournalfiles | false | 是否忽略丟失的journal文件。若是爲false,當丟失了journal文件時,broker啓動時會拋異常並關閉 |
checkForCorruptJournalFiles | false | 檢查消息文件是否損壞,true,檢查發現損壞會嘗試修復 |
checksumJournalFiles | false | 產生一個checksum,以便可以檢測journal文件是否損壞。 |
property name | default value | Comments |
---|---|---|
*archiveDataLogs | false | 當爲true時,歸檔的消息文件被移到directoryArchive,而不是直接刪除 |
*directoryArchive | null | 存儲被歸檔的消息文件目錄 |
databaseLockedWaitDelay | 10000 | 在使用負載時,等待得到文件鎖的延遲時間,單位ms |
maxAsyncJobs | 10000 | 等待寫入journal文件的任務隊列的最大數量。應該大於或等於最大併發producer的數量。配合並行存儲轉發屬性使用。 |
concurrentStoreAndDispatchTopics | false | 若是爲true,轉發消息的時候同時提交事務 |
concurrentStoreAndDispatchQueues | true | 若是爲true,轉發Topic消息的時候同時存儲消息的message store中 |
property name | default value | Comments |
---|---|---|
archiveCorruptedIndex | false | 是否歸檔錯誤的索引到Archive文件夾下 |
property name | default value | Comments |
---|---|---|
IndexDirectory | 單獨設置KahaDB中,db.data文件的存儲位置。若是不進行設置,db.data文件的存儲位置仍是將以directory屬性設置的值爲準 |
LevelDb是可以處理十億級別規模Key-Value型數據持久性存儲的C++ 程序庫,由Google發起並開源。LevelDB只能由本操做系統的其餘進程調用,因此它不具備網絡性。若是您須要網絡上的遠程進程操做LevelDB,那麼就要自行封裝服務層。
LevelDB中的核心設計算法是跳躍表(Skip List),核心操做策略是對磁盤上的數據日誌結構進行歸併(LSM)。跳躍表其實是二叉平衡樹的一種變形結構,它經過將一個有序鏈表進行「升維」操做,從而減小每一層上須要遍歷的數據數量,達到快速查找的目的。下圖示意了一個跳躍表結構(在實際工做中,跳躍表的層級和「升維」策略的不一樣,跳躍表的結構也不同):
您能夠將上圖中的每一個元素節點,想象成每一條消息的key值。爲了講解方便,上圖中我將擁有所有數據的元素的跳躍層稱爲Level 2(最高層),但實際上規範的跳躍表結構中,擁有所有元素的層次稱爲Level 0(最底層)。跳躍表的結構並不是一成不變,當有一條新的記錄須要插入到結構時,可能會引發表中的多個Level都發生變化。
那麼LevelDB是如何應用跳躍表結構的?又是如何進行歸併操的?咱們首先來看看LevelDB的簡要結構:
當LevelDB收到新的消息是會同步寫兩個地方:內存中的MemTable區域和磁盤上的Log文件。直接寫Log文件是爲了在系統異常退出並重啓時,可以將LevelDB恢復到退出前的結構;那麼有的讀者會問,因爲是直接寫磁盤會不會成爲性能瓶頸呢?答案是,LevelDB的log文件操做採用預佔磁盤空間(默認爲100MB),進行順序寫的方式。而且這個過程能夠設置爲異步的(固然若是設置成異步的,可能須要接受異常狀況下數據丟失的風險)。
LevelDB還寫將消息寫入內存的MemTable區域,MemTable區域的的數據組織結構就是跳躍表(Skip List),這樣的數據組織結構能夠在讀取內存中信息的時候,快速完成信息定位。當MemTable區域的數據量達到indexWriteBufferSize屬性設置的大小時(默認爲6MB),LevelDB就會把這個MemTable區域標記爲Immutable,並開啓一個新的MemTable區域。必定注意,是標記爲Immutable,而不是把MemTable區域的數據拷貝到某一個Immutable區域。
新標記的Immutable區域中的數據會被執行Compact操做,從而寫入到磁盤上的.sst文件中。所謂Compact操做是指:LevelDB會剔除Immutable區域中那些已經被標示爲「刪除」的數據(成功消費的數據就會被標記爲「刪除」),排除那些格式錯誤的數據,並可能進行數據壓縮。
SSTable文件是指存在於硬盤上,後綴名爲.sst的文件。這些文件是LevelDB磁盤上最重要的數據記錄文件,每個SSTable文件的默認大小爲2MB,也就是說LevelDB的文件夾下會有不少的.sst文件。SSTable文件並非順序寫的,而是按照數據的key排序進行隨機寫,因此SSTable文件無需預佔存儲磁盤存儲空間。
借鑑於跳躍表的設計思想,SSTable文件也是分層次的。每一層可存儲的數據量是上一層的的10倍。舉個例子,第Level 2層可存儲的數據量80MB,那麼第Level 3層可存儲的數據量就是800MB。當某一層可存儲的數據量達到最大值,LevelDB就會從當層選取一個.sst文件,向下層作Compact操做,因爲來自於上層的新數據,因此下層的.sst文件內容將產生變化(上文說過,.sst文件中的內容是按照數據的key排序的)。
每個SSTable文件,由多個Block塊構成(默認大小爲4KB),block塊是LevelDB讀寫磁盤上SSTable文件的最小單元。每個SSTable文件最後一個Block塊稱爲Index Block,它指明瞭SSTable文件中每個Data block的起始位置。
可是每次讀取某個Block塊時,若是都在磁盤上先去找Index Block,而後再根據其中記錄的index,找到Block在文件的起始位置的話,查找效率顯然不高。因此LevelDB的內存區域中,有一個稱爲Block Cache的區域。這個區域存儲着衆多的Index Block,這樣就不須要到磁盤上查找Index Block了。
那麼衆多的.sst文件是如何被管理的呢?要知道若是在衆多.sst文件中進行某條消息的查找時,若是將某一層的.sst文件所有進行遍歷,那麼性能確定是不能接受的。在LevelDB中有一類文件被稱爲Manifest,這些Manifest文件記錄了sst文件的關鍵信息,包括(但不限於):某個.sst文件屬於哪個Level、這個.sst文件中最小的key值、這個.sst文件中最大的key值。
在ActiveMQ中配置使用LevelDB做爲持久化存儲方案實際上很簡單,使用主配置文件中的persistenceAdapter標記就能夠完成。最簡配置以下所示:
......
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
......
<persistenceAdapter>
<levelDB directory="${activemq.data}/levelDB"/>
</persistenceAdapter>
......
</broker>
......
以上示例配置中,directory屬性表示LevelDB的結構文件所放置的目錄位置。請注意,因爲log文件是順序寫的機制,因此log文件也會預佔磁盤空間,而且log文件默認的大小就是100MB。那麼只要生成一個log文件,就至少會佔據100MB的存儲空間(但這不表明總的已使用量)。也就是說,若是您將主配置文件中storeUsage標記的limit屬性設置爲200mb,那麼透過ActiveMQ管理界面看到的現象就是:只要有任何一條PERSISTENT Message被接受,Store percent used馬上就會變成50%。若是您將storeUsage標記的limit屬性爲100mb,那麼只要有任何一條PERSISTENT Message被接受,ActiveMQ服務端的Producer Flow Control策略就會馬上開始工做。
因此必定不要吝嗇分配memoryUsage、storeUsage。依據您的團隊在生產環境下的存儲方案,也能夠經過logSize屬性改變LevelDB中單個log文件的大小。以下示例:
......
<!-- 限制成50mb -->
<persistenceAdapter>
<levelDB directory="${activemq.data}/levelDB" logSize="52428800"/>
</persistenceAdapter>
......
上一小節咱們介紹到,默認的LevelDB存儲策略中,當ActiveMQ接收到一條消息後,就會同步將這條消息寫入到log文件中,而且同時在內存區域向Memtable寫入位置索引。經過配置您也能夠將這個過程改成「異步」:
......
<!-- 改成異步寫log文件 -->
<persistenceAdapter>
<levelDB directory="${activemq.data}/levelDB" logSize="52428800" sync="false"/>
</persistenceAdapter>
......
如下列表展現了您可使用的LevelDB的配置屬性,使用「*」標識出來的屬性是筆者認爲重要的配置項:
property name | default value | Comments |
---|---|---|
*directory | 「LevelDB」 | 數據文件的存儲目錄 |
sync | true | 是否進行磁盤的同步寫操做 |
*logSize | 104857600 (100 MB) | log日誌文件的最大值 |
verifyChecksums | false | 是否對從文件系統中讀取的數據進行強制校驗校驗 |
paranoidChecks | false | 若是LevelDB檢測到數據錯誤,則儘快將錯誤在存儲位置進行標記 |
indexFactory | org.fusesource.leveldbjni.JniDBFactory, org.iq80.leveldb.impl.Iq80DBFactory | 建立LevelDB時使用的工廠類,因爲LevelDB的本質是C++程序庫,因此Java是經過Jni進行底層調用的 |
*indexMaxOpenFiles | 1000 | 可供索引使用的打開文件的數量,這是由於Level內部使用了多線程進行文件讀寫操做 |
indexWriteBufferSize | 6291456 (6 MB) | 內存MemTable的最大值,若是MemTable達到這個值,就會被標記爲Immutable |
indexBlockSize | 4096 (4 K) | 每一個讀取到內存的SSTable——Index Block數據的大小 |
*indexCacheSize | 268435456 (256 MB) | 使用一個內存區域記錄多個Level中,SSTable——Index Block數據,以便讀操做時,不通過遍歷就可直接定位數據在某個level中的位置,建議增大該區域 |
indexCompression | snappy | 適用於索引塊的壓縮類型,影響Compression策略 |
logCompression | none | 適用於日誌記錄的壓縮類型,影響Compression策略 |
從ActiveMQ V4版本開始,ActiveMQ就支持使用關係型數據庫進行持久化存儲——經過JDBC實現的數據庫鏈接。能夠支持的關係型數據庫包括(但不限於):Apache Derby、DB二、HSQL、Informix、MySQL、Oracle、Postgresql、SQLServer、Sybase。
下面向各位讀者演示如何爲ActiveMQ配置Mysql數據庫服務。前提是您已經某個網絡位置準備好了Mysql服務,並能夠成功進行遠程登陸。
......
<broker>
......
<!-- 配置ActiveMQ鏈接到Mysql服務 -->
<!-- 記得去掉原來的KahaDB或者LevelDB的配置 -->
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql_datasource" createTablesOnStartup="true"/>
</persistenceAdapter>
......
</broker>
<!-- 演示使用的是C3p0鏈接池,固然您也可使用DBCP鏈接池 -->
<!-- 就是spring的配置文件結構 -->
<bean id="mysql_datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activemqdb?relaxAutoCommit=true&useUnicode=true&characterEncoding=utf-8"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="30"/>
<property name="initialPoolSize" value="10"/>
</bean>
......
在配置關係型數據庫做爲ActiveMQ的持久化存儲方案時,要注意幾個事項:
配置信息建議放置在您的jetty.xml配置文件中,也能夠放置在activemq.xml配置文件中。除此以外,還要記得須要使用到的相關jar文件放置到ActiveMQ安裝路徑下的./lib目錄。例如使用mysql + c3p0的配置中,須要的jar包至少包括:mysql-jdbc驅動的jar包和c3p0的jar包。
在jdbcPersistenceAdapter標籤中,咱們設置了createTablesOnStartup屬性爲true,這是爲了在第一次啓動ActiveMQ時,ActiveMQ服務節點會自動建立所須要的數據表。啓動完成後,能夠去掉這個屬性,或者更改createTablesOnStartup屬性爲false。
在配置和測試的過程當中,您能夠會遇到這樣的問題:「java.lang.IllegalStateException: BeanFactory not initialized or already closed」這是由於您的操做系統的機器名中有「_」符號。更改機器名而且重啓後,便可解決問題。
在一樣的硬件資源條件下,相比KahaDB和LevelDB這樣的「內存+存儲介質」這樣的持久化方案而言,使用關係型數據庫做爲ActiveMQ的持久化方案絕對不能說「性能」最好,可是在大多數狀況下這個持久化方案也不會成爲整個頂層架構的設計瓶頸(由於關係型數據庫通常都有本身的熱備和負載方案)。因此不少團隊仍是會使用這樣的持久化方案,很大一部分緣由就是這些團隊對關係型數據庫有更豐富的使用經驗,且有專門的數據庫管理人員。
以上咱們介紹了三種持久化存儲方案:KahaDB、LevelDB、關係型數據庫。其中KahaDB和LevelDB的工做原理基本相似,都採用內存+磁盤介質的方案:內存用於存放信息的位置索引,磁盤介質上存放消息內容。而關係型數據庫的方案,ActiveMQ將徹底經過JDBC對數據庫進行操做完成消息的存儲和修改。
可是不是如網絡上一些資料所說的那樣,必定要對三種持久化存儲方案的速度作比較後,選擇最快的那種存儲方案呢?這裏面至少有兩個誤區:
下面咱們進行詳細的討論:
根據不一樣的硬件層配置,同一種持久化存儲方案的性能是徹底不同的。例如在單節點計算的狀況下,選用DDR 2133雙通道內存組和DDR3 1333單通道內存條從理論上至少就能夠多得到4Gbps的帶寬;選用一樣支持SATA3規範的機械硬盤和SSD固態硬盤,雖然二者理論上的對外速度都標稱6Gbps,可是因爲機械硬盤上單磁頭的讀寫速度存在瓶頸,因此就算進行連續讀操做,速度也只能達到200MB/s左右;可是固態硬盤的連續讀速度卻能夠達到500MB/s左右(基本已經接近6Gbps)。
若是是企業級硬件存儲方案,那麼速度差別還會繼續擴大。例如電信行業常常採用的IBM 各個系列磁盤陣列,通常都會配置諸如RAID5這樣的軟存儲方案。這樣一來,同一份文件有多個副本,而且有多個磁頭負責讀寫。磁盤陣列的對外輸出通常會採用光纖通道(FC),而光纖通道行業協會(Fibre Channel Industry Association)最新推出的(2015年實施)Gen 6第6代光纖通道標準中,設計的對外傳輸理論速度是128Gbps。
固然,除非您的公司/團隊可以接受這些企業級存儲方案高昂的費用。不然仍是建議在生產環境搭建性價比較高的折中方案。例如採用20臺左右PC Server搭建Ceph/MFS分佈式存儲系統。這個方案,咱們將在下一篇文章中進行詳細說明。
因此某種存儲方案的性能,除了這種存儲方案的工做原理之外對其有直接影響外,還要考慮它的工做環境。只有根據軟件團隊預估的系統壓力、綜合建設方案、考慮後續擴容方式,來肯定採用哪種存儲方案,纔是科學的。