ActiveMQ系列—ActiveMQ性能優化(下1)(消息存儲方案 KahaDB)

序1:存儲方案配置

在介紹ActiveMQ的存儲方案之前,首先需要明確的是ActiveMQ中的幾種“容量”描述:

ActiveMQ的內核是Java編寫的,也就是說如果服務端沒有Java運行環境ActiveMQ是無法運行的。ActiveMQ啓動時,啓動腳本使用wrapper包裝器來啓動JVM。JVM相關的配置信息在啓動目錄的“wrapper.conf”配置文件中。各位讀者可以通過改變其中的配置項,設置JVM的初始內存大小和最大內存大小(當然還可以進行其他和JVM有關的設置,例如開啓debug模式),如下:

[root@bogon linux-x86-64]# pwd
/usr/local/src/apache-activemq-5.13.2/bin/linux-x86-64
[root@bogon linux-x86-64]# ls
activemq  libwrapper.so  wrapper  wrapper.conf
[root@bogon linux-x86-64]# vim wrapper.conf

......

# Initial Java Heap Size (in MB)
#wrapper.java.initmemory=3

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=1024

......

以上配置項設置JVM的初始內存大小爲100MB,設置JVM的最大內存大小爲512MB。如果您在更改後使用console參數啓動ActiveMQ,那麼會看到當前ActiveMQ的JVM設置發生了變化:

這裏寫圖片描述

明確了ActiveMQ的內存區域來源,纔好理解後續的設置內容。ActiveMQ每一個服務節點都是一個獨立的進程。在ActiveMQ主配置文件中,讀者可以找到一個“systemUsage”標記,類似定義如下:

          <!--
            The systemUsage controls the maximum amount of space the broker will
            use before disabling caching and/or slowing down producers. For more information, see:
            http://activemq.apache.org/producer-flow-control.html
          -->
          <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並不是“最大可用空間”,而是一個閥值。

序2:持久化存儲方案的演化

說到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集羣存儲方案。


9、KahaDB存儲方案

9.1、KahaDB基本結構

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@bogon kahadb]# pwd
/usr/local/src/apache-activemq-5.13.2/data/kahadb
[root@bogon kahadb]# ll -h
總用量 3.2M
-rw-r--r-- 1 root root 32M 9月  21 08:13 db-1.log
-rw-r--r-- 1 root root 32K 9月  21 08:13 db.data
-rw-r--r-- 1 root root 33K 9月  21 08:13 db.redo
-rw-r--r-- 1 root root   8 9月  21 08:10 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的主配置文件中進行設置。

9.2、在ActiveMQ中配置KahaDB

由於在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文件是否損壞。



5.4版本之後有效的屬性:

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中



5.6版本之後有效的屬性:

property name default value Comments
archiveCorruptedIndex false 是否歸檔錯誤的索引到Archive文件夾下



5.10版本之後有效的屬性:

property name default value Comments
IndexDirectory 單獨設置KahaDB中,db.data文件的存儲位置。如果不進行設置,db.data文件的存儲位置還是將以directory屬性設置的值爲準
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章