ActiveMq——消息持久化

什麼是持久化消息?

保證消息只被傳送一次和成功使用一次。在持久性消息傳送至目標時,消息服務將其放入持久性數據存儲。如果消息服務由於某種原因導致失敗,它可以恢復此消息並將此消息傳送至相應的消費者。雖然這樣增加了消息傳送的開銷,但卻增加了可靠性

1.消息可靠性之持久化

1.1 queue消息非持久和持久

隊列默認是持久化的

在這裏插入圖片描述

 // 非持久化
 messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 持久化    
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
public class JmsProduce {
    public static final String ACTIVEMQ_URL = "tcp://118.24.20.3:61626";
    public static final String QUEUE_NAME = "jdbc01";

    public static void main(String[] args) throws  Exception{
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageProducer messageProducer = session.createProducer(queue);
        // 非持久化
        messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
        for (int i = 1; i < 4 ; i++) {
            TextMessage textMessage = session.createTextMessage("---MessageListener---" + i);
            messageProducer.send(textMessage);
        }
        messageProducer.close();
        session.close();
        connection.close();
        System.out.println("  **** 消息發送到MQ完成 ****");
    }
}

1.2 Topic消息非持久和持久
topic默認就是非持久化的,因爲生產者生產消息時,消費者也要在線,這樣消費者才能消費到消息。
topic消息持久化,只要消費者向MQ服務器註冊過,所有生產者發佈成功的消息,該消費者都能收到,不管是MQ服務器宕機還是消費者不在線

注意:
1.一定要先運行一次消費者,等於向MQ註冊,類似我訂閱了這個主題。
2.然後再運行生產者發送消息。
3.之後無論消費者是否在線,都會收到消息。如果不在線的話,下次連接的時候,會把沒有收過的消息都接收過來。

// 持久化topic 的消息生產者
public class JmsProduce_persistence {

    public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
    public static final String TOPIC_NAME = "topic01";

    public static void main(String[] args) throws  Exception{
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        javax.jms.Connection connection = activeMQConnectionFactory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Topic topic = session.createTopic(TOPIC_NAME);
        MessageProducer messageProducer = session.createProducer(topic);

        // 設置持久化topic 
        messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
        // 設置持久化topic之後再,啓動連接
        connection.start();
        for (int i = 1; i < 4 ; i++) {
            TextMessage textMessage = session.createTextMessage("topic_name--" + i);
            messageProducer.send(textMessage);
            MapMessage mapMessage = session.createMapMessage();
        }
        messageProducer.close();
        session.close();
        connection.close();
        System.out.println("  **** TOPIC_NAME消息發送到MQ完成 ****");
    }
}

// 持久化topic 的消息消費者
public class JmsConsummer_persistence {
    public static final String ACTIVEMQ_URL = "tcp://192.168.17.3:61616";
    public static final String TOPIC_NAME = "topic01";

    public static void main(String[] args) throws Exception{
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        Connection connection = activeMQConnectionFactory.createConnection();
// 設置客戶端ID。向MQ服務器註冊自己的名稱
        connection.setClientID("marrry");
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Topic topic = session.createTopic(TOPIC_NAME);
// 創建一個topic訂閱者對象。一參是topic,二參是訂閱者名稱
        TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic,"remark...");
         // 之後再開啓連接
        connection.start();
        Message message = topicSubscriber.receive();
         while (null != message){
             TextMessage textMessage = (TextMessage)message;
             System.out.println(" 收到的持久化 topic :"+textMessage.getText());
             message = topicSubscriber.receive();
         }
        session.close();
        connection.close();
    }
}

控制界面顯示:
在這裏插入圖片描述

2.消息可靠性之事務

在這裏插入圖片描述

(1)生產者開啓事務後,執行commit方法,這批消息才真正的被提交。不執行commit方法,這批消息不會提交。執行rollback方法,之前的消息會回滾掉。生產者的事務機制,要高於簽收機制,當生產者開啓事務,簽收機制不再重要。
(2)消費者開啓了事務就必須手動提交,不然會重複消費消息

// 創建會話session,兩個參數transacted=事務,acknowledgeMode=確認模式(簽收)
        // 消費者開啓了事務就必須手動提交,不然會重複消費消息
 final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
 
 session.commit();

3.消息可靠性之簽收

1. 自動簽收(Session.AUTO_ACKNOWLEDGE):該方式是默認的。該種方式,無需我們程序做任何操作,框架會幫我們自動簽收收到的消息。
2.手動簽收(Session.CLIENT_ACKNOWLEDGE):手動簽收。該種方式,需要我們手動調用Message.acknowledge(),來簽收消息。如果不簽收消息,該消息會被我們反覆消費,只到被簽收

  • 開啓了事務的情況下,開啓了手動簽收
  • connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);,如果沒有提交事務,沒有執行commit(),就算執行了應答textMessage.acknowledge(),還是會重複消費。
  • 如果執行了commit,沒有進行手動應答textMessage.acknowledge(),不會產生重複消費。

4.消息持久化機制之JDBC

4.1開啓docker 中的activemq,並且進入到activeMq的文件目錄中

在這裏插入圖片描述

在這裏插入圖片描述

4.2將mysql -connector -javajar包導入到容器內的lib

在這裏插入圖片描述

4.3jdbcPersistenceAdapter配置 修改配置文件activemq.xml。將之前的替換爲jdbc的配置。如下:
<!--  
<persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
      </persistenceAdapter>
-->
<persistenceAdapter>  
      <jdbcPersistenceAdapter dataSource="#mysql-ds" createTableOnStartup="true"/> 
</persistenceAdapter>
4.4數據庫連接池配置 需要我們準備一個mysql數據庫,並創建一個名爲activemq的數據庫。新建的數據庫要採用latin1 或者ASCII編碼

在 < /broker > 標籤和< import>標籤之間插入數據庫連接池配置

    </broker>

    <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:// 192.168.40.1/activemq?relaxAutoCommit=true"/>
        <property name="username" value="activemq"/>
        <property name="password" value="123456"/>
        <property name="poolPreparedStatements" value="true"/>
    </bean>

    <import resource="jetty.xml"/>

ACTIVEMQ_MSGS數據表:
在這裏插入圖片描述

ACTIVEMQ_ACKS數據表:
在這裏插入圖片描述

ACTIVEMQ_LOCK數據表:
在這裏插入圖片描述

5.消息持久化之JDBC with ActiveMQ Journal

這種方式克服了JDBC Store的不足,JDBC每次消息過來,都需要去寫庫讀庫。ActiveMQ Journal,使用高速緩存寫入技術,大大提高了性能。當消費者的速度能夠及時跟上生產者消息的生產速度時,journal文件能夠大大減少需要寫入到DB中的消息。
舉個例子:生產者生產了1000條消息,這1000條消息會保存到journal文件,如果消費者的消費速度很快的情況下,在journal文件還沒有同步到DB之前,消費者已經消費了90%的以上消息,那麼這個時候只需要同步剩餘的10%的消息到DB。如果消費者的速度很慢,這個時候journal文件可以使消息以批量方式寫到DB。
爲了高性能,這種方式使用日誌文件存儲+數據庫存儲。先將消息持久到日誌文件,等待一段時間再將未消費的消息持久到數據庫。該方式要比JDBC性能要高

5.1 配置

在這裏插入圖片描述

6.總結

① jdbc效率低,kahaDB效率高,jdbc+Journal效率較高。
② 持久化消息主要指的是:MQ所在服務器宕機了消息不會丟試的機制。
③ 持久化機制演變的過程:
從最初的AMQ Message Store方案到ActiveMQ V4版本退出的High Performance Journal(高性能事務支持)附件,並且同步推出了關於關係型數據庫的存儲方案。ActiveMQ5.3版本又推出了對KahaDB的支持(5.4版本後被作爲默認的持久化方案),後來ActiveMQ 5.8版本開始支持LevelDB,到現在5.9提供了標準的Zookeeper+LevelDB集羣化方案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章