消息中间件-ACTIVEMQ-8:ActiveMQ的消息存储和持久化

目录

1:ActiveMQ的持久化简介

2:AMQ Meassage Store (了解):

3:KahaDB(默认):

1:基于日志文件,从5.4开始默认的持久化插件;

2:默认的配置在/conf/activemq.xml

3:KahaDB的存储原理

4:KahaDBdata中的文件介绍

4:LevelDB存储(了解)

5:JDBC消息存储(http://activemq.apache.org/persistence)

1:将mysql数据库的jar包导入到mq服务器

2:修改activemq.xml,增加数据库配置bean

3:修改activemq.xml的jdbcPersistenceAdapter的标签引用数据库配置

4:创建activemq数据库,后重新启动activemq会自动生成对应表

1:activemq_msgs用于存储消息,Queue和Topic都存储在这个表中:

2:activemq_acks用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存:

3:表activemq_lock在集群环境中才有用,只有一个Broker可以获得消息,称为Master Broker,

5:代码验证测试---(一定要开启持久化)

1:队列

2:主题

6:总结

6:增强的JDBC,高速缓存Journal

1:jounal的持久化适配器---配置

2:重启后,代码不变就已经启动了高速缓存;生产者产生消息后如果短时间内没有被消费掉,那么这些消息才会进入数据库落地;

7:持久化总结


1:ActiveMQ的持久化简介

为避免意外宕机后丢失信息,需要做到重启后可以恢复消息队列;系统消息一般都会采用可持久化机制

ActiveMQ的消息持久化机制有JDBC,AMQ,KahaDB,LevelDB,无论使用那种持久化机制,消息的存储逻辑是一样的;

就是在发送者将发送消息后,消息中心首先将数据存储在本地文件夹;内存数据库或者远程数据库;然后再发送给接受者,若成功就从存储中删除,失败则继续推送;

消息中心启动后首先检查指定的存储位置,如果有未发送的消息,则需要把消息发送出去;

 

2:AMQ Meassage Store (了解):

是一种文件存储机制,以前默认的存储机制,AMQ适用于ActiveMQ5.3以前的机制;

3:KahaDB(默认):

1:基于日志文件,从5.4开始默认的持久化插件;

2:默认的配置在/conf/activemq.xml

3:KahaDB的存储原理

1:消息存储是一个事务日志和仅仅使用一个索引文件来存储他所有的位置

2:数据被追加到data logs里面,当不需要log文件中数据的时候,log文件就会被丢弃;

4:KahaDBdata中的文件介绍

1:db-1.log文件

2:db.data

3:db.free:当前db.data那些页是空闲的,文件具体内容是所有空闲也的id

4:db.redo用来进行消息恢复,如果Kaha消息存储在强制退出后启动,用于恢复BTree索引;

5:lock文件锁,表示当前获得KahaDB读写权限的broker

4:LevelDB存储(了解)

5:JDBC消息存储(http://activemq.apache.org/persistence)

1:将mysql数据库的jar包导入到mq服务器

如果想使用其他数据库,就将其他数据库连接jar包和pooljiar包放进去

2:修改activemq.xml,增加数据库配置bean

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

3:修改activemq.xml的jdbcPersistenceAdapter的标签引用数据库配置

 

4:创建activemq数据库,后重新启动activemq会自动生成对应表

1:activemq_msgs用于存储消息,Queue和Topic都存储在这个表中:

ID:自增的数据库主键

CONTAINER:消息的Destination

MSGID_PROD:消息发送者客户端的主键

MSG_SEQ:是发送消息的顺序,MSGID_PROD+MSG_SEQ可以组成JMS的MessageID

EXPIRATION:消息的过期时间,存储的是从1970-01-01到现在的毫秒数

MSG:消息本体的Java序列化对象的二进制数据

PRIORITY:优先级,从0-9,数值越大优先级越高

队列消息存贮:

主题存储:

 

2:activemq_acks用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存:

主要的数据库字段如下:

CONTAINER:消息的Destination

SUB_DEST:如果是使用Static集群,这个字段会有集群其他系统的信息

CLIENT_ID:每个订阅者都必须有一个唯一的客户端ID用以区分

SUB_NAME:订阅者名称

SELECTOR:选择器,可以选择只消费满足条件的消息。条件可以用自定义属性实现,可支持多属性AND和OR操作

LAST_ACKED_ID:记录消费过的消息的ID。

 

3:表activemq_lock在集群环境中才有用,只有一个Broker可以获得消息,称为Master Broker,

其他的只能作为备份等待Master Broker不可用,才可能成为下一个Master Broker。
这个表用于记录哪个Broker是当前的Master Broker。

 

5:代码验证测试---(一定要开启持久化)

1:队列

生产者:

package com.wkl.queuq;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.jms.*;

/**
 * Description:第一次连接ActvieMq的服务
 * Date:       2020/9/3 - 下午 1:51
 * author:     wangkanglu
 * version:    V1.0
 */
public class Produce {

    /*账号密码如果都是默认的admin,可以不用穿;直传url*/
    private static  final String USERNAME = "admin";
    private static  final String PASSWORD = "admin";
    /*这个url以tcp协议开头,java程序访问的是61616端口*/
    private static  final String ACTIVE_URL = "tcp://192.168.43.122:61616";
    private static  final String Queue_NAME = "queue01";

    public static void main(String[] args) throws JMSException {
        //1:创建连接工厂,按照给定的账号,密码,url地址来链接;
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,ACTIVE_URL);
        //2:通过链接工厂获得connection并启动
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3:通过connection创建会话,参数分别是事务和签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4:创建目的地(队列还是主题)
        Queue queue = session.createQueue(Queue_NAME);
        //5:创建消息生产者
        MessageProducer producer = session.createProducer(queue);
        /*---------开启持久化-----------*/
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);

        //6:通过消息生产者producer产生3条消息发到mq的队列中
        for (int i = 1; i <=5 ; i++) {
            //7:创建消息
            TextMessage textMessage = session.createTextMessage("msg--" + i);
            //8:通过perducer发送给mq
            producer.send(textMessage);
        }

        //9:关闭资源;顺着申请,倒着关闭
        producer.close();
        session.close();
        connection.close();

        System.out.println("---end---");

    }
}

 

消费者:

package com.wkl.queuq;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * Description:消息的消费者就是处理者的helloword
 * Date:       2020/9/3 - 下午 2:38
 * author:     wangkanglu
 * version:    V1.0
 */
public class Consumer {

    /*账号密码如果都是默认的admin,可以不用穿;直传url*/
    private static  final String USERNAME = "admin";
    private static  final String PASSWORD = "admin";
    /*这个url以tcp协议开头,java程序访问的是61616端口*/
    private static  final String ACTIVE_URL = "tcp://192.168.43.122:61616";
    private static  final String Queue_NAME = "queue01";

    public static void main(String[] args) throws JMSException {
        System.out.println("1-----");
        //1:创建连接工厂,按照给定的账号,密码,url地址来链接;
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,ACTIVE_URL);
        //2:通过链接工厂获得connection并启动
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3:通过connection创建会话,参数分别是事务和签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4:创建目的地(队列还是主题)
        Queue queue = session.createQueue(Queue_NAME);
        //5:创建消息消费者
        MessageConsumer consumer = session.createConsumer(queue);
        //消息的消费者循环读取读取消息
        while(true){
            //6:consumer读取消息,当初发送消息是testMessage,接受时也是这个类型
            //消费者只等待4秒;4秒后没消息就走了
            TextMessage textMessage = (TextMessage) consumer.receive(4000L);
            if(null!=textMessage){
                System.out.println("接收到的消息:"+textMessage.getText());
//                textMessage.acknowledge();
            }else {
                break;
            }
        }
        //7:关闭资源;顺着申请,倒着关闭
        consumer.close();
        session.close();
        connection.close();

        System.out.println("----end----");
    }
}

 

2:主题

订阅者:

package com.wkl.PersistenceTopic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;
import java.io.IOException;

/**
 * Description:持久化的消费者改造
 * Date:       2020/9/3 - 下午 8:29
 * author:     wangkanglu
 * version:    V1.0
 */
public class Consumer {

    /*账号密码如果都是默认的admin,可以不用穿;直传url*/
    private static  final String USERNAME = "admin";
    private static  final String PASSWORD = "admin";
    /*这个url以tcp协议开头,java程序访问的是61616端口*/
    private static  final String ACTIVE_URL = "tcp://192.168.43.122:61616";
    private static final String TOPIC_NAME = "topic01";

    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("zhangsan");
        //1:创建连接工厂,按照给定的账号,密码,url地址来链接;
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,ACTIVE_URL);
        //2:通过链接工厂获得connection并启动
        Connection connection = activeMQConnectionFactory.createConnection();
        //设定是谁订阅了我
        connection.setClientID("zhansan");
        //3:通过connection创建会话,参数分别是事务和签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4:创建目的地(队列还是主题)
        Topic topic = session.createTopic(TOPIC_NAME);

        //创建主题订阅者
        TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic,"备注。。。");

        //5:启动
        connection.start();

        Message message = topicSubscriber.receive();
        while(null!=message){
            TextMessage textMessage = (TextMessage) message;
            System.out.println("收到消息:" + textMessage.getText());
            message = topicSubscriber.receive(5000L);
        }


        session.close();
        connection.close();

        System.out.println("----end----");
    }
}

 

发布者:

package com.wkl.PersistenceTopic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * Description:持久化的topic生产
 * Date:       2020/9/3 - 下午 8:20
 * author:     wangkanglu
 * version:    V1.0
 */
public class Produce {

    /*账号密码如果都是默认的admin,可以不用穿;直传url*/
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "admin";
    /*这个url以tcp协议开头,java程序访问的是61616端口*/
    private static final String ACTIVE_URL = "tcp://192.168.43.122:61616";
    private static final String TOPIC_NAME = "topic01";

    public static void main(String[] args) throws JMSException {
        //1:创建连接工厂,按照给定的账号,密码,url地址来链接;
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, ACTIVE_URL);
        //2:通过链接工厂获得connection并启动
        Connection connection = activeMQConnectionFactory.createConnection();
        //3:通过connection创建会话,参数分别是事务和签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4:创建目的地(队列还是主题)
        Topic topic = session.createTopic(TOPIC_NAME);
        //5:创建消息生产者
        MessageProducer producer = session.createProducer(topic);

        producer.setDeliveryMode(DeliveryMode.PERSISTENT);

        //先表明持久化才启动
        connection.start();

        //6:通过消息生产者producer产生3条消息发到mq的主题中
        for (int i = 1; i <= 3; i++) {
            //7:创建消息
            TextMessage textMessage = session.createTextMessage("TOPICmsg--" + i);

            //8:通过perducer发送给mq
            producer.send(textMessage);
        }

        //9:关闭资源;顺着申请,倒着关闭
        producer.close();
        session.close();
        connection.close();

        System.out.println("---end---");
    }
}

订阅者消费完了;对应的消息这个还存在; 

6:总结

1:用哪个数据库,就将相应的jar包放进mq的lib文件夹中

2:设置数据库连接bean的时候,mysql5,和mysql8是不同的;不同的驱动和不同的url 

3:createTablesOnStartup属性第一次启动创建表后;记得把他这只为false

6:增强的JDBC,高速缓存Journal

1:jounal的持久化适配器---配置

<persistenceFactory> 
    <journalPersistenceAdapterFactory 
        journalLogFiles="5"
        journalLogFileSize="32768"
        useJournal="true"
        useQuickJournal="true"
        dataSource="#mysql-ds" 
        dataDirectory="activemq-data" />
</persistenceFactory>

2:重启后,代码不变就已经启动了高速缓存;生产者产生消息后如果短时间内没有被消费掉,那么这些消息才会进入数据库落地;

7:持久化总结

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苍煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值