ActiveMQ 9.ActiveMQ的消息存儲與持久化

ActiveMQ

@Author:hanguixian

@Email:[email protected]

九 ActiveMQ的消息存儲與持久化

  • 官網: http://activemq.apache.org/persistence

1 是什麼

  • 爲了避免意外宕機以後丟失信息,需要做到重啓後可以恢復消息隊列,消息系統一般都會採用持久化機制。
  • ActiveMQ的消息持久化機制有JDBC,AMQ,KahaDB和LevelDB,無論使用哪種持久化方式,消息的存儲邏輯都是一致的。
  • 在發送者將消息發送出去後,消息中心首先將消息存儲到本地數據文件、內存數據庫或者遠程數據庫等,再試圖將消息發送給接收者,成功則將消息從存儲中刪除,失敗則繼續嘗試發送。
  • 消息中心啓動以後首先要檢查指定的存儲位置,如果有未發送成勘的消息,則需要把消息發送出去。

2 有哪些

2.1 AMQ Message Store

  • 基於文件的存儲方式,是以前的默認消息存儲,現在不用了

  • AMQ是一種文件存儲形式,它具有寫入速度快和容易恢復的特點。消息存儲在一個個文件中,文件的默認大小爲32M,當一個存儲文件中的消息己經全部被消費,那麼這個文件將被標識爲可刪除,在下一個清除階段,這個文件被刪除。AMQ適用於ActiveMQ5.3之前的版本

2.2 KahaDB消息存儲(默認)

  • 基於日誌文件,從ActiveMQ 5.4開始默認的持久化插件

  • 官網: http://activemq.apache.org/kahadb

    • KahaDB is a file based persistence database that is local to the message broker that is using it. It has been optimized for fast persistence. It is the the default storage mechanism since ActiveMQ 5.4. KahaDB uses less file descriptors and provides faster recovery than its predecessor, the AMQ Message Store[KahaDB 是一個基於文件的持久性數據庫,它是使用它的消息代理的本地數據庫。它針對快速持久性進行了優化。它是自ActiveMQ 5.4以來的默認存儲機制。KahaDB使用的文件描述符較少,並且比其前身AMQ 消息存儲提供更快的恢復]
  • 驗證: 在 activeMQ.xml 配置文件中可以看到 默認的持久化插件是KahaDB

 <!--
            Configure message persistence for the broker. The default persistence
            mechanism is the KahaDB store (identified by the kahaDB tag).
            For more information, see:

            http://activemq.apache.org/persistence.html
 -->
<persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
  • 說明

    • KahaDB是目前默認的存儲方式,可用於任何場景,提高了性能和恢復能力。
    • 消息存儲使用一個事務日誌和僅僅用一個索引文件來存儲它所有的地址。
    • KahaDB是一個專門針對消息持久化的解決方案,它對典型的消息使用模式進行了優化。
    • 數據被追加到data logs中。當不再需要log文件中的數據時,log文件會被丟棄
    • 存在位置:activeMQ安裝目錄data下的kahadb
  • KahaDB 的 存 儲 原 理

    • kahadb在消息保存目錄中只有四類文件和一個lock,跟activeMQ的其他文件存儲引擎相比這就非常簡潔了。

      • db-1.log(可能會有多個 db-number.log)
      • db.data
      • db.free
      • db.redo
      • lock
    • db-<Number>.log KahaDB存儲消息到預定義大小的數據記錄文件中,文件命名爲db-<Number>.log 當數據文件己滿時,一個新的文件會隨之創建,number數值也會隨之遞增,它隨着消息數量的增多,如每32M一個文件,文件名按照數字進行編號,如db-1.log、db-2.log、…。當不再有引用到數據文件中的任何消息時,文件會被刪除或歸檔。

kahaDB-1.png

  • db.data該文件包含了持久化的BTree索引,索引了消息數據記錄中的消息,它是消息的索引文件,本質上是B-Tree(B樹),使用B-Tree作爲索引指向db-.log裏面存儲的消息。

  • db.free當前db.data文件裏哪些頁面是空閒的,文件具體內容是所有空閒頁的ID

  • db.redo用來進行消息恢復,如果KahaDB消息存儲在強制退出後啓動,用於恢復BTree索引。

  • lock文件鎖,表示當前獲得kahadb讀寫權限的broker。

2.3 JDBC消息存儲

  • 消息基於JDBC存儲

2.4 LevelDB消息存儲

  • 這種文件系統是從ActiveMQ5.8之後引進的,它和KahaDB非常相似,也是基於文件的本地數據庫儲存形式,但是它提供比KahaDB更快的持久性。但它不使用自定義B-Tree實現來索引預寫日誌,而是使用基於LevelDB的索引
  • 默認配置如下:
<persistenceAdapter> 
	<levelDBdirectory="activemq-data"/> 
</persistenceAdapter> 

2.5 JDBC Message store with ActiveMQ Journal

  • For long term persistence we recommend using JDBC coupled with our high performance journal. You can use just JDBC if you wish but its quite slow.[對於長期持久性,我們建議使用 JDBC 和高性能日誌。你可以只使用JDBC,如果你想,但它相當緩慢。]

3 JDBC消息存儲

  1. 準備mysql數據庫

  2. 添加mysql數據庫的驅動包到lib文件夾中(我使用的是mysql-connector-java-5.1.37.jar)

  3. persistenceAdapter配置:在conf路徑下修改activemq.xml配置文件

<!--  <persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
        </persistenceAdapter> -->

<persistenceAdapter>
    <jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="true"/>
</persistenceAdapter>

<!-- dataSource指定將要引用的持久化數據庫bean名稱,createTablesOnStartup是否在啓動的時候創建數據表,默認值是true,這樣每次啓動都會去創建數據表了,一般是第一次啓動的時候設置爲true,之後改成false.  -->
  1. 數據庫連接池配置
<bean id="mysql-ds" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> 
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/activemq_persistence?relaxAutoCommit=true"/> 
        <property name="username" value="root"/> 
        <property name="password" value="123456"/> 
        <property name="poolPreparedStatements" value="true"/> 
</bean>

<!-- 注意:添加位置在 </broker> 之後 ,在  <import resource="jetty.xml"/> 之前-->
  1. 建立數據庫和數據表
    1. 建一個和上面url中配置的數據庫名相同的數據庫,這裏就建一個名爲activemq_persistence的數據庫
    2. 在第一啓動,正常的情況下會建立三張表ACTIVEMQ_MSGS,ACTIVEMQ_LOCK,ACTIVEMQ_MSGS。
    3. ACTIVEMQ_MSGS(消息表,queue和topic都存在裏面),字段說明
      1. ID:自增的數據庫主鍵
      2. CONTAINER:消息的Destination
      3. MSGID_PROD:消息發送者的主鍵
      4. MSG_SEQ:是發送消息的順序,MSGID_PROD+MSG_SEQ可以組成JMS的MessageID
      5. EXPIRATION:消息的過期時間,存儲的是從1970-01-01到現在的亳秒數
      6. MSG:消息本體的Java序列化對象的二進制數據
      7. PRIORITY:優先級,從0-9,數值越大優先級越高
    4. ACTIVEMQ_ACKS 用於存儲訂閱關係,存儲持久訂閱的信息和最後一個持久訂閱接收的消息ID。如果是持久化Topic,訂閱者和服務器的訂閱關係在這個表保存。數據庫字段如下:
      1. CONTAINER:消息的Destination
      2. SUB_DEST:如果是使用Static集羣,這個字段會有集羣其他系統的信息
      3. CLIENT_ID:每個訂閱者都必須有一個唯一的客戶端ID用以區分
      4. SUBNAME: 訂閱者名稱
      5. SELECTOR:選擇器,可以選擇只消費滿足條件的消息。條件可以用自定義屬性實現,可支持多屬性AND和OR操作
      6. LAST_ACKED_ID:記錄消費過的消息的ID
    5. ACTIVEMQ_LOCK 在集羣環境中才有用,只有一個Broker可以獲得消息,稱爲Master Broker,其他的只能作爲備份等待Master Broker不可用,纔可能成爲下一個Master Broker.這個表用於記錄哪個Broker是當前的Master Broker.
  2. 代碼運行檢驗
    1. 一定要開啓持久化messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
    2. 運行隊列代碼檢驗
    3. 運行發佈/訂閱代碼檢驗
  3. 數據庫情況
    1. 在點對點類型,當DeliveryMode設置爲NON_PERSISTENT時,消息被保存在內存中;當DeliveryMode設置爲PERSISTENT時,消息保存在broker的相應文件或數據庫中;而且點對點類型中消息一旦被Consumer小就從broker中刪除,數據庫中的數據會被立即清除。
    2. 發佈/訂閱類型:消息消費後數據庫中依然會有消費歷史記錄

4 JDBC Message store with ActiveMQ Journal

  • Journal介紹

    • 這種方式克服了JDBC Store的不足,JDBC每次消息過來,都需要去寫庫和讀庫。
    • ActiveMQ Journal,使用高速緩存寫入技術,大大提高了性能。
    • 當消費者的消費速度能夠及時跟上生產者消息的生產速度時,journal文件能夠大大減少需要寫入到DB中的消息。
    • 舉個例子,生產者生產了1000條消息,這1000條消息會保存到Journal文件,如果消費者的消費速度很快的情況下,在Journal文件還沒有同步到DB之前,消費者己經消費了90%的以上的消息,那麼這個時候只需要同步剩餘的10%的消息到DB;如果消費者的消費速度很慢,這個時候Journal文件可以使消息以批量方式寫到DB
  • 配置

      <!--  <persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
        </persistenceAdapter> -->
      <!--  <persistenceAdapter>
             <jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="true"/>
        </persistenceAdapter> -->

    <persistenceFactory>
      <journalPersistenceAdapterFactory journalLogFiles="4" journalLogFileSize="32789" 
        useJournal="true" 
        useQuickJournal="true"
        dataSource="#mysql-ds"
        dataDirectory="activemq-data" /> 
    </persistenceFactory> 
  • 使用Journal後,消息首先會被保存到緩存中,一段時候後纔會放到數據庫中,提升了性能。

5 小總結

  1. 如果是queue:在沒有消費者消費的情況下會將消息保存到activemq_msgs表中,只要有任意一個消費者已經消費過了,消費之後這些消息將會立即被刪除。
  2. 如果是topic:一般是先啓動消費訂閱然後再生產的情況下會將消息保存到activemq_acks。
  3. 開發遇到的坑(在配置關係型數據庫作爲ActiveMQ的持久化存儲方案時,有坑)
    1. 數據jar包:記得需要使用到的相關jar文件放置到ActiveMQ安裝路徑下的lib目錄。mysq-jdbc驅動ar包和對應的數據庫連接池jar包
    2. createTablesOnStaltup屬性:在jdbcPersistenceAdapter標籤中設置了createTablesOnStartup屬性爲true時在第一次啓動ActiveMQ時,ActiveMQ服務節點會自動創建所需要的數據表。啓動完成後可以去掉這個屬性,或者更改爲false
    3. 下滑線:java.lang.IllegalStateException:BeanFactory not initialized or already closed這是因爲您的操作系統的機器名中有“_”符號。請更改機器名並且重啓後即可解決問題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章