ActiveMQ的安装与使用

ActiveMQ的安装与使用
一、安装
1、下载安装包
官网下载地址: http://activemq.apache.org/components/classic/download/
根据自己的电脑的系统下载对应的版本.
在这里插入图片描述

2、解压
cd 到下载压缩包的目录,解压压缩包,输入 tar -zxvf +文件名即可解压
tar zxvf apache-activemq-5.16.0-bin.tar.gz
在这里插入图片描述

3、启动
进入相对目录: /apache-activemq-5.16.0/bin/macosx

命令行输入./activemq start 启动ActiveMQ
启动成功后,会看到 Broker
在这里插入图片描述

4、访问
游览器输入地址: http://127.0.0.1:8161/admin/ 访问
账号和密码默认为: admin/admin
在这里插入图片描述

二、使用场景
1、业务场景说明:
消息队列在大型电子商务类网站,如京东、淘宝、去哪儿等网站有着深入的应用,
队列的主要作用是消除高并发访问高峰,加快网站的响应速度。
在不使用消息队列的情况下,用户的请求数据直接写入数据库,在高并发的情况下,会对数据库造成巨大的压力,同时也使得系统响应延迟加剧。
在使用队列后,用户的请求发给队列后立即返回,
(例如: 当然不能直接给用户提示订单提交成功,京东上提示:您“您提交了订单,请等待系统确认”),
再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。
由于消息队列的服务处理速度远快于数据库,因此用户的响应延迟可得到有效改善。
在这里插入图片描述

2、消息队列应用场景
消息队列在实际应用中常用的使用场景。异步处理、应用解耦、流量削锋和消息通讯四个场景
2.1. 异步处理
场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种1.串行的方式;2.并行方式。
在这里插入图片描述

(1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
在这里插入图片描述

(2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。

假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。
因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。
则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)。
小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?
引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:
在这里插入图片描述

按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。
注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,
因此用户的响应时间可能是50毫秒。所以基于此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。
2.2. 应用解耦
场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图:
在这里插入图片描述

传统模式的缺点:
1) 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败;
2) 订单系统与库存系统耦合;
如何解决以上问题呢?引入应用消息队列后的方案,如下图:

在这里插入图片描述

1:订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功,请等待物流配送。
2:库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
3:假如:在下单时库存系统不能正常使用。也不影响正常下单,
因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。

2.3. 流量削锋
流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用容易挂掉。为解决这个问题,一般需要在应用前端加入消息队列。

1、可以控制活动的人数.
2、可以缓解短时间内高流量压垮应用;
在这里插入图片描述

1、用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面;
2、秒杀业务根据消息队列中的请求信息,再做后续处理。
2.4. 消息通讯
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。

点对点通讯:
在这里插入图片描述

客户端A和客户端B使用同一队列,进行消息通讯。
聊天室通讯:
在这里插入图片描述

客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。
以上实际是消息队列的两种消息模式,点对点或发布订阅模式。

三、功能菜单介绍
1、queue消息队列页面 (点对点模式)
在这里插入图片描述

Name : 消息队列名称
Number Of Pending Messages:未被消费的消息数目
Number Of Consumers:消费者数量
Messages Enqueued :进入队列的消息,进入队列的消息总消息数目,包括已被消费和未被消费的消息数目.这个 数目只增不减.
Messages Dequeued :出了队列的消息,可以理解为是被消费的消息数量,在queues里和它进入队列的总数量相等(因为一个消息之后被成功消费一次.)如果暂时不等,是因为消费者还没来得及消费.
2、topic主题页面(发布订阅模式)
在这里插入图片描述

Name : 主题名称
Number Of Pending Messages:未被消费的消息数目
Number Of Consumers:消费者数量
Messages Enqueued : 进入队列的消息,进入队列的消息总数目,包括已被消费和未被消费的,这个数目只增不减.
Messages Dequeued :出了队列的消息,可以理解为是被消费的掉的消息数量,在topics里,因为多消费者从而导致数量会比入队数目要高.
3、Subscribers查看订阅者页面
在这里插入图片描述

查看订阅这个消息,只在Topics消息类型这个页面才会有数据.
4、Connections 查看连接数页面
在这里插入图片描述

四、ActiveMQ 相关概念
1、 java消息服务
不同系统之间的信息交换,是我们开发中比较常见的场景,比如系统A要把数据发送给系统B,这个问题我们应该如何去处理? 1999年,原来的SUN公司领衔提出了一种面向消息的中间件服务–JMS规范(标准);常用的几种信息交互技术(httpClient、hessian、dubbo、jms、webservice 五种).
2、JMS概述
JMS即Java消息服务(Java Message Service的简称),是Java EE 的标准/规范之一。这种规范(标准)指出:消息的发送应该是异步的、非阻塞的。也就是说消息的发送者发送完消息后就直接返回了,不需要等待接收者返回后才能返回,发送者和接收者可以说是互不影响。所以这种规范(标准)能够减轻或消除系统瓶颈,实现系统之间去除耦合,提高系统的整体可伸缩性和灵活性。JMS只是Java EE中定义的一组标准API,它自身并不是一个消息服务系统,它是消息传送服务的一个抽象,也就是说它定义了消息传送的接口而并没有具体实现。
3、ActiveMQ概述
我们知道JMS只是消息服务的一组规范和接口,并没有具体的实现,而ActiveMQ就是JMS规范的具体实现;ActiveMQ是Apache软件基金会的开源产品,支持AMQP协议、MQTT协议(和XMPP协议作用类似)、Openwire协议和Stomp协议等多种消息协议。并且ActiveMQ完整支持JMS API接口规范,Apache也提供多种其他语言的客户端,例如:C、C++、C#、Ruby、Perl。

4、ActiveMQ与JMS关系
我们知道,JMS只是定义了一组有关消息传送的规范和标准,并没有真正实现,也就说JMS只是定义了一组接口而已;就像JDBC抽象了关系数据库访问、JPA抽象了对象与关系数据库映射、JNDI抽象了命名目录服务访问一样,JMS具体的实现由不同的消息中间件厂商提供,比如Apache ActiveMQ就是JMS规范的具体实现,Apache ActiveMQ才是一个消息服务系统,而JMS不是。
在这里插入图片描述

5、ActiveMQ 架构
在这里插入图片描述

ActiveMQ主要涉及到5个方面:

  1. 传输协议:消息之间的传递,无疑需要协议进行沟通,启动一个ActiveMQ打开了一个监听端口, ActiveMQ提供了广泛的连接模式,其中主要包括SSL、STOMP、XMPP;ActiveMQ默认的使用的协议是openWire,端口号:61616;
  2. 消息域:ActiveMQ主要包含Point-to-Point (点对点),Publish/Subscribe Model (发布/订阅者),其中在Publich/Subscribe 模式下又有Nondurable subscription和durable subscription (持久化订阅)2种消息处理方式
  3. 消息存储:在消息传递过程中,部分重要的消息可能需要存储到数据库或文件系统中,当中介崩溃时,信息不回丢失
  4. Cluster (集群): 最常见到 集群方式包括network of brokers和Master Slave;
  5. Monitor (监控) :ActiveMQ一般由jmx来进行监控
    默认配置下的ActiveMQ只适合学习代码而不适用于实际生产环境,ActiveMQ的性能需要通过配置挖掘,其性能提高包括代码级性能、规则性能、存储性能、网络性能以及多节点协同方法(集群方案),所以我们优化ActiveMQ的中心思路也是这样的:
  6. 优化ActiveMQ单个节点的性能,包括NIO模型选择和存储选择。
  7. 配置ActiveMQ的集群(ActiveMQ的高性能和高可用需要通过集群表现出来)。
    五、ActiveMQ的通信方式
    1、点对点(p2p)
    专门用于使用队列Queue传送消息;基于队列Queue的点对点消息只能被一个消费者消费,如多个消费者都注册到同一个消息队列上,当生产者发送一条消息后,而只有其中一个消费者会接收到该消息,而不是所有消费者都能接收到该消息。
    点对点模式下一条消息将会发送给一个消息消费者,如果当前Queue没有消息消费者,消息将进行存储。
    在这里插入图片描述

2、发布/订阅(Publish/Subscribe)
发布/订阅模型采用的是主题(Topic)作为消息通讯载体。该模式类似微信公众号的模式。发布者发布一条信息,然后将该信息传递给所有的订阅者。注意:订阅者想要接收到该信息,必须在该信息发布之前订阅。
在这里插入图片描述

Publishe:是属于发布信息的一方,它通过定义一个或者多个topic,然后给这些topic发送消息。
3、两种模式区别

比较项目Topic 模式队列Queue 模式队列
工作模式“订阅-发布”模式,如果当前没有订阅者,消息将会被丢弃。如果有多个订阅者,那么这些订阅者都会收到消息“负载均衡”模式,如果当前没有消费者,消息也不会丢弃;如果有多个消费者,那么一条消息也只会发送给其中一个消费者,并且要求消费者ack信息。
有无状态无状态Queue数据默认会在mq服务器上以文件形式保存,比如Active MQ一般保存在$AMQ_HOME\data\kr-store\data下面。也可以配置成DB存储
传递完整性如果没有订阅者,消息会被丢弃消息不会丢弃
处理效率由于消息要按照订阅者的数量进行复制,所以处理性能会随着订阅者的增加而明显降低,并且还要结合不同消息协议自身的性能差异由于一条消息只发送给一个消费者,所以就算消费者再多,性能也不会有明显降低。当然不同消息协议的具体性能也是有差异的

六、具体实现
1、引入jar 包
注意:不同的jdk 版本对应不同的jar包

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.15.0</version>
</dependency>

2、消息生产者实现
1、:建立ConnectionFactory工厂对象,需要填入用户名、密码、及其连接地址:均用默认即可.

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
        ActiveMQConnectionFactory.DEFAULT_USER,
        ActiveMQConnectionFactory.DEFAULT_PASSWORD,
        "failover:(tcp://localhost:61616)?Randomize=false");

2、通过ConnectionFactory工厂对象建立一个Connection对象连接,并调用 Connection的start的方法开启连接.Connection默认是关闭的

Connection connection = connectionFactory.createConnection();
connection.start();

3、通过调用Connection连接对象创建一个Session会话(上下文环境对象),用于接收消息,参数配置为1 是否启用事物,参数为2为签手模式,一般设置自动签收.

Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

4、通过Session创建Destination对象,指的是一个客户端用来生产消息和消息消息来源的对象.在PTP(点对点)模式中,Destination被称为Queue队列.在pub/sub模式(发布订阅模式),Destination被称为Topic主题.整个程序中存在多个Queue和Topic.

Destination destination = session.createQueue("Hello!");

5、通过Session 创建 MessageProducer(消息生产者)
MMessageProducer producer = session.createProducer(null);

6、 可以使用MessageProducer的setDeliveryMode方法为其设置持久化特性和非持久化特性(DeliveryMode),我们稍后详细介绍。
// Persistent 用来指定JMS Provider对消息进行持久化操作,以免Provider fail的时候,丢失Message. 持久化数据默认在data目录下.
地址: https://blog.csdn.net/rubulai/article/details/97034214?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
// NON_Persistent 方式下的JMS Provider不会对消息进行持久化,JMS Provider会将相应的消息存在内存中,当Consumer连接上时,再发送过去,但在Provider fail的时候,Message会丢失。

producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

7、最后我们使用JMS规范的TextMessage(文本)形式创建数据(通过Session对象),并用MessageProducer的send方法发送数据。同理客户端使用receive方法进行接收数据。最后不要忘记关闭Connection连接。

for(int i = 0 ; i < 10 ; i ++){
    TextMessage msg = session.createTextMessage("我是消息内容" + i);
    // 第一个参数目标地址
    // 第二个参数 具体的数据信息
    // 第三个参数 传送数据的模式
    // 第四个参数 优先级
    // 第五个参数 消息的过期时间
    producer.send(destination, msg, DeliveryMode.NON_PERSISTENT, 0 , 1000L);
    System.out.println("发送消息:" + msg.getText());
    session.commit(); //启用事务时记得提交事务,不然消费端接收不到消息
    Thread.sleep(1000);
}

if(connection != null){
    connection.close();
}

3、消息消费者实现
1、:建立ConnectionFactory工厂对象,需要填入用户名、密码、及其连接地址:均用默认即可.

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
        ActiveMQConnectionFactory.DEFAULT_USER,
        ActiveMQConnectionFactory.DEFAULT_PASSWORD,
        "failover:(tcp://localhost:61616)?Randomize=false");

2、通过ConnectionFactory工厂对象建立一个Connection对象连接,并调用 Connection的start的方法开启连接.Connection默认是关闭的

Connection connection = connectionFactory.createConnection();
connection.start();

3、通过调用Connection连接对象创建一个Session会话(上下文环境对象),用于接收消息,参数配置为1 是否启用事物,参数为2为签手模式,一般设置自动签收.

Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

4、通过Session创建Destination对象,指的是一个客户端用来生产消息和消息消息来源的对象.在PTP(点对点)模式中,Destination被称为Queue队列.在pub/sub模式(发布订阅模式),Destination被称为Topic主题.整个程序中存在多个Queue和Topic.

Destination destination = session.createQueue("Hello!");

5、通过Session 创建 MessageConsumer(消息消费者)

MessageConsumer consumer = session.createConsumer(destination);

while(true){
    TextMessage msg = (TextMessage)consumer.receive();
    if(msg == null) {
        break;
    }
    System.out.println("收到的消息:" + msg.getText());
}

4、启动消息生产者产生消息,可在ActiveMQ的网页管理中看到消息的状态。

Number Of Pending Messages:未被消费的消息数目为1
5、启动消息消费者消费消息,可在ActiveMQ的网页管理中看到消息的状态。

Messages Enqueued :进入队列的消息,进入队列的消息总消息数目,包括已被消费和未被消费的消息数目.这个数目只增不减.
Messages Dequeued :出了队列的消息,可以理解为是被消费的消息数量,在queues里和它进入队列的总数量相等(因为一个消息之后被成功消费一次.)如果暂时不等,是因为消费者还没来得及消费.

Messages Enqueued: 10 生产了10条消息
Messages Dequeued: 10 消费了10条消息
6、(PTP)点对点通信方式具体实现
生产者

/**
 *  点对点 生产者
 * @throws Exception
 */
public void testMQProducerQueue() throws Exception{
    //1、创建工厂连接对象,需要制定ip和端口号
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
            ActiveMQConnectionFactory.DEFAULT_USER,
            ActiveMQConnectionFactory.DEFAULT_PASSWORD,
            "failover:(tcp://localhost:61616)?Randomize=false");
//2、使用连接工厂创建一个连接对象
Connection connection = connectionFactory.createConnection();
//3、开启连接
 connection.start();
//4、使用连接对象创建会话(session)对象
 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5、使用会话对象创建目标对象,包含queue和topic(一对一和一对多)
 Queue queue = session.createQueue("test-queue");
//6、使用会话对象创建生产者对象
 MessageProducer producer = session.createProducer(queue);
//7、使用会话对象创建一个消息对象
  TextMessage textMessage = session.createTextMessage("hello!test-queue");
//8、发送消息
  producer.send(textMessage);
//9、关闭资源
    producer.close();
    session.close();
    connection.close();
}

消费者

/**
 *  点对点 消费者
 * @throws Exception
 */
public void TestMQConsumerQueue() throws Exception{
    //1、创建工厂连接对象,需要制定ip和端口号
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
            ActiveMQConnectionFactory.DEFAULT_USER,
            ActiveMQConnectionFactory.DEFAULT_PASSWORD,
            "failover:(tcp://localhost:61616)?Randomize=false");
    //2、使用连接工厂创建一个连接对象
    Connection connection = connectionFactory.createConnection();
    //3、开启连接
    connection.start();
    //4、使用连接对象创建会话(session)对象
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    //5、使用会话对象创建目标对象,包含queue和topic(一对一和一对多)
    Queue queue = session.createQueue("test-queue");
    //6、使用会话对象创建生产者对象
    MessageConsumer consumer = session.createConsumer(queue);
    //7、向consumer对象中设置一个messageListener对象,用来接收消息
    consumer.setMessageListener(new MessageListener() {

        @Override
        public void onMessage(Message message) {
            // TODO Auto-generated method stub
            if(message instanceof TextMessage){
                TextMessage textMessage = (TextMessage)message;
                try {
                    System.out.println(textMessage.getText());
                } catch (JMSException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    });
    //8、程序等待接收用户消息
    System.in.read();
    //9、关闭资源
    consumer.close();
    session.close();
    connection.close();
}

7、(订阅/发布)通信方式实现

生产者
/**
 *   订阅发布 生产者
 * @throws Exception
 */
public void TestTopicProducer() throws Exception{
    //1、创建工厂连接对象,需要制定ip和端口号
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
            ActiveMQConnectionFactory.DEFAULT_USER,
            ActiveMQConnectionFactory.DEFAULT_PASSWORD,
            "failover:(tcp://localhost:61616)?Randomize=false");
    //2、使用连接工厂创建一个连接对象
    Connection connection = connectionFactory.createConnection();
    //3、开启连接
    connection.start();
    //4、使用连接对象创建会话(session)对象
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    //5、使用会话对象创建目标对象,包含queue和topic(一对一和一对多)
    Topic topic = session.createTopic("test-topic");
    //6、使用会话对象创建生产者对象
    MessageProducer producer = session.createProducer(topic);
    //7、使用会话对象创建一个消息对象
    TextMessage textMessage = session.createTextMessage("hello!test-topic");
    //8、发送消息
    producer.send(textMessage);
    //9、关闭资源
    producer.close();
    session.close();
    connection.close();
}

消费者
/**
 *   订阅发布 消费者
 * @throws Exception
 */
public void TestTopicConsumer() throws Exception{
    //1、创建工厂连接对象,需要制定ip和端口号
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
            ActiveMQConnectionFactory.DEFAULT_USER,
            ActiveMQConnectionFactory.DEFAULT_PASSWORD,
            "failover:(tcp://localhost:61616)?Randomize=false");
    //2、使用连接工厂创建一个连接对象
    Connection connection = connectionFactory.createConnection();
    //3、开启连接
    connection.start();
    //4、使用连接对象创建会话(session)对象
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    //5、使用会话对象创建目标对象,包含queue和topic(一对一和一对多)
    Topic topic = session.createTopic("test-topic");
    //6、使用会话对象创建生产者对象
    MessageConsumer consumer = session.createConsumer(topic);
    //7、向consumer对象中设置一个messageListener对象,用来接收消息
    consumer.setMessageListener(new MessageListener() {

        @Override
        public void onMessage(Message message) {
            // TODO Auto-generated method stub
            if(message instanceof TextMessage){
                TextMessage textMessage = (TextMessage)message;
                try {
                    System.out.println(textMessage.getText());
                } catch (JMSException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    });
    //8、程序等待接收用户消息
    System.in.read();
    //9、关闭资源
    consumer.close();
    session.close();
    connection.close();
}

7、JMS消息类型
JMS定义了五种消息正文格式,以及消息的调用类型,允许发送和接收一些不同类型的数据,提供现有消息格式的一些级别的兼容性。

1、StreamMessage:–JAVA原始的数据流
StreamMessage streamMessage = session.createStreamMessage(); streamMessage.writeString(“streamMessage流消息”); streamMessage.writeLong(55);

2、TextMessage:一个字符串对象
TextMessage textMessage = session.createTextMessage(“文本消息”);

3、ObjectMessage:一个系列化的java对象

  1. User user = new User(“cjm”, “对象消息”); //User对象必须实现Serializable接口
  2. ObjectMessage objectMessage = session.createObjectMessage();
  3. objectMessage.setObject(user);

4、BytesMessage:一个字节对象
String s = “BytesMessage字节消息”;
BytesMessage bytesMessage = session.createBytesMessage(); bytesMessage.writeBytes(s.getBytes());

5、MapMessage:key/value方式的键值对
MapMessage mapMessage = session.createMapMessage(); mapMessage.setLong(“age”, new Long(32)); mapMessage.setDouble(“sarray”, new Double(5867.15)); mapMessage.setString(“username”, “键值对消息”);
七、ActiveMQ的消息存储持久化
有效的消息存储
ActiveMQ提供了一个插件式的消息存储,类似于消息的多点传播,主要实现了如下几种:
1.AMQ消息存储-基于文件的存储,以前默认的存储方式
2.KahaDB消息存储-提供了容量的提升和恢复能力,现在的默认方式
3.JDBC消息存储-消息基于JDBC存储
4.Memory消息存储-基于内存的消息存储
https://www.cnblogs.com/qlqwjy/p/10480357.html

1、kahaDB消息存储–目前默认的存储方式
KahaDB是目前默认的存储方式,可用于任何场景,提高了性能和恢复能力。消息存储使用一个事务日志和仅仅用一个索引文件来存储它所有的地址。
KahaDB是一个专门针对消息持久化的解决方案,它对典型的消息使用模式进行了优化。在kaha中,数据被追加到 data logs中。 当不再需要log文件中的数据的时候,log文件会被丢弃。
1、基本配置方式:
在activemq的安装目录下的:conf/activemq.xml中有如下配置:(默认配置)

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

在这里插入图片描述
如上面配置了文件的位置,现在我们查看kahadb的文件位置:

2、可用属性

  1. director: KahaDB存放的路径,默认值activemq-data
  2. indexWriteBatchSize: 批量写入磁盘的索引page数量,默认值为1000
  3. indexCacheSize: 内存中缓存索引page的数量,默认值10000
  4. enableIndexWriteAsync: 是否异步写出索引,默认false
  5. journalMaxFileLength: 设置每个消息data log的大小,默认是32MB
  6. enableJournalDiskSyncs: 设置是否保证每个没有事务的内容,被同步写入磁盘,JMS持久化的时候需要,默认为true
  7. cleanupInterval: 在检查到不再使用的消息后,在具体删除消息前的时间,默认30000
  8. checkpointInterval: checkpoint的间隔时间,默认是5000
  9. ignoreMissingJournalfiles: 是否忽略丢失的消息日志文件,默认false
  10. checkForCorruptJournalFiles: 在启动的时候,将会验证消息文件是否损坏,默认false
  11. checksumJournalFiles: 是否为每个消息日志文件提供checksum,默认false
  12. archiveDataLogs: 是否移动文件到特定的路径,而不是删除它们,默认false
  13. directoryArchive: 定义消息已经被消费过后,移动data log到的路径,默认null
  14. databaseLockedWaitDelay: 获得数据库锁的等待时间(used by shared master/slave),默认10000。用于之后主从复制的时候配置
  15. maxAsyncJobs: 设置最大的可以存储的异步消息队列,默认值10000,可以和concurrent MessageProducers设置成一样的值。
  16. concurrentStoreAndDispatchTransactions:是否分发消息到客户端,同时事务存储消息,默认true
  17. concurrentStoreAndDispatchTopics: 是否分发Topic消息到客户端,同时进行存储,默认true
  18. concurrentStoreAndDispatchQueues: 是否分发queue消息到客户端,同时进行存储,默认true
    3、Java内嵌Broker使用kahadb的例子
package cn.qlq.activemq.broker;

import java.io.File;

import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.store.kahadb.KahaDBStore;

public class BrokerUeingKahadb {
    public static void main(String[] args) throws Exception {
        BrokerService brokerService = new BrokerService();
        File dataKahadbFile = new File("data/kahadb");

        KahaDBStore kahaDBStore = new KahaDBStore();
        kahaDBStore.setDirectory(dataKahadbFile);
        kahaDBStore.setJournalDiskSyncInterval(1024 * 1000);
        kahaDBStore.setIndexWriteBatchSize(100);
        kahaDBStore.setEnableIndexWriteAsync(true);

        brokerService.setPersistenceAdapter(kahaDBStore);
        brokerService.addConnector("tcp://localhost:61616");
        brokerService.start();
    }
}

2、AMQ Message Store消息存储
1、概述
AMQ Message Store是ActiveMQ5.0缺省的持久化存储,它是一个基于文件、事务存储设计为快速消息存储的一个结构,该结构是以流的形式来进行消息交互的。
  这种方式中,Messages被保存到data logs中,同时被reference store进行索引以提高存取速度。Data logs由一些简单的data log文件组成,缺省的文件大小是32M,如果某个消息的大小超过了data log文件的大小,那么可以修改配置以增加data log文件的大小。如果某个data log文件中所有的消息都被成功消费了,那么这个data log文件将会被标记,以便在下一轮的清理中被删除或者归档。
2、配置
用下面的配置方式替换掉activemq.xml的 persistenceAdapter 即可,也就是该配置需要作为broker的属性



3、JDBC消息储存
ActiveMQ支持使用JDBC来持久化消息,我们只需要配置JDBC驱动即可,至于表结构activemq会自动帮我们建好表结构。
配置如下:
(1)拷贝mysql的驱动包 mysql-connector-java-5.1.37-bin.jar 到 apache-activemq-5.15.8\lib\optional\ 目录下
(2)修改apache-activemq-5.15.8\conf\activemq.xml
首先定义dataSource(该dataSource位于apache-activemq-5.15.8\lib\optional\ commons-dbcp2-2.1.1.jar包内,当然可以换成我们自己的c3p0,durid等连接池)

com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/activemq root 123456 修改broker的persistenceAdapter持久化方式: (3)启动项目发现activemq会自动帮我们创建好表结构,如下三张表: mysql> show tables; +--------------------+ | Tables_in_activemq | +--------------------+ | activemq_acks | | activemq_lock | | activemq_msgs | +--------------------+ 3 rows in set (0.00 sec)

解释上面三张表:
  1.消息表,缺省表明为ACTIVEMQ_MSGS, queue和topic都存储在里面
    ID:自增主键; CONTAINER:所属类型以及所在队列或者主题; MSGID_PROD:生产者ID;MSGID_SEQ:在同一批次消息中的序号; EXPIRATION:过期时间(表示永不过期); MSG:序列化之后的消息; PRIORITY优先级; XID:暂时不知道这个有什么用。
  2.ACTIVEMQ_ACKS表存储持久订阅的信息和最后一个持久订阅接收的消息ID
    CONTAINER:与上面消息表的CONTAINER一样; SUB_DEST:子目的地,与CONTAINER一样;
    CLIENT_ID: 链接的客户端ID,也就是我们程序:connection.setClientID(“cc1”); 产生的ID
    SUB_NAME:持久订阅者的名称.也就是我们程序: session.createDurableSubscriber(destination, “C11”); 产生的名称
    SELECTOR:消息选择器,consumer可以选择自己想要的
    LAST_ACKED_ID:最后一次确认ID,这个字段存的该该订阅者最后一次收到的消息的ID
    XID:暂时不知道这个有什么用。
  3.锁定表,缺省表名为ACTIVEMQ_LOCK,用来确保在某一时刻,只能有一个ActiveMQ broker实例来访问数据库
    XID:自增的主键
    TIME:日期
    BROKER_NAME:占用数据库的brokerName

Java内嵌Broker使用JDBC持久化存储
依赖的jar包

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200909133134381.png#pic_center)

2、broker启动的代码
package cn.qlq.activemq;

import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter;
import org.apache.commons.dbcp2.BasicDataSource;

public class BrokerUsingJDBC {
public static void main(String[] args) throws Exception {
BrokerService brokerService = new BrokerService();

    // 1.创建数据源
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setUrl("jdbc:mysql://localhost:3306/activemq");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    
    // 2.创建JDBCPersistenceAdapter
    JDBCPersistenceAdapter Adapter = new JDBCPersistenceAdapter();
    Adapter.setDataSource(dataSource);

    brokerService.setBrokerName("brokerName");
    brokerService.setUseJmx(true);
    brokerService.setPersistenceAdapter(Adapter);
    brokerService.addConnector("tcp://localhost:61616");
    brokerService.start();
}

}

补充:JDBC Message Store with ActiveMQ Journal====优化版的JDBC存储
  这种方式克服了JDBC Store的不足,使用快速的缓存写入技术,大大提高了性能。
  JDBC 配合其自带的 high performance journal;根据官方说法,它内置的高性能journal的工作类似于在缓存层工作,消息会优先写入到journal,后台的定时任务会每隔一段时间间隔去。
JDBC Store和JDBC Message Store with ActiveMQ Journal的区别:
  1. JDBC with journal的性能优于jdbc
  2. JDBC用于master/slave模式的数据库分享
  3. JDBC with journal不能用于master/slave模式
  4. 一般情况下,推荐使用jdbc with journal

其配置方式如下:注释掉原来的持久化适配器,并注入持久化工厂

    <persistenceFactory>
        <journalPersistenceAdapterFactory journalLogFiles="4" journalLogFileSize="32768" useJournal="true" useQuickJournal="true" dataSource="#mysql_ds" dataDirectory="activemq-data"/>
    </persistenceFactory>

(1)需要的jar包:

在这里插入图片描述
(2)Broker启动类:

package cn.qlq.activemq;

import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.store.journal.JournalPersistenceAdapterFactory;
import org.apache.commons.dbcp2.BasicDataSource;

public class BrokerUsingJDBC {
    public static void main(String[] args) throws Exception {
        BrokerService brokerService = new BrokerService();
    // 1.创建数据源
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setUrl("jdbc:mysql://localhost:3306/activemq");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");

    // 2.创建PersistenceAdapterFactory
    JournalPersistenceAdapterFactory persistenceFactory = new JournalPersistenceAdapterFactory();
    persistenceFactory.setDataSource(dataSource);
    persistenceFactory.setJournalLogFiles(4);
    persistenceFactory.setJournalLogFileSize(32768);
    persistenceFactory.setUseJournal(true);
    persistenceFactory.setUseQuickJournal(true);

    // 3.设置持久化工厂并启动broker
    brokerService.setBrokerName("brokerName");
    brokerService.setUseJmx(true);
    brokerService.setPersistenceFactory(persistenceFactory);
    brokerService.addConnector("tcp://localhost:61616");
    brokerService.start();
}

}
4、Memory Message Store
内存消息存储主要是存储所有的持久化的消息在内存中。这里没有动态的缓存存在,所以你必须注意设置你的broker所在的JVM和内存限制。
这种方式的持久化消息只在当前JVM内有效,当重启JVM之后会丢失持久化的消息。
配置方式如下:只需要将 persistent 属性设为false即可

<broker xmlns="http://activemq.apache.org/schema/core" persistent="false" brokerName="brokerName" dataDirectory="${activemq.data}">

其内嵌Java的broker方式如下:
BrokerService brokerService = new BrokerService();

    brokerService.setPersistent(false);
    brokerService.setBrokerName("brokerName");
    brokerService.setUseJmx(true);
    brokerService.addConnector("tcp://localhost:61616");
    brokerService.start();

八、ActiveMQ死信队列
1、简介
DLQ-死信队列列(Dead Letter Queue)用来保存处理理失败或者过期的消息。

出现以下情况时,消息会被redelivered

  1. A transacted session is usedand rollback() is called(使 用 一个事务session,并且调用了了rollback() 方法).

  2. A transacted session is closedbefore commit is called( 一个事务session,关闭之前调 用了了 commit).

  3. A session is usingCLIENT_ACKNOWLEDGE and Session.recover() is called(在session中使 用CLIENT_ACKNOWLEDGE签收模式,并且调 用了了Session.recover()方法).

当 一个消息被redelivered超过maximumRedeliveries(缺省为6次,具体设置请参考后面的内容)次数时,会给broker发送 一个"Poison ack",这个消息被认为是a poison pill(毒丸),这时broker会将这个消息发送到DLQ,以便便后续处理理。

登录ActiveMQ管理理端可以看到ActiveMq有 一个默认的死信队:ActiveMQ.DLQ ,若未做设置则处理理失败的消息会自动进 入此队列列。缺省持久消息过期,会被送到DLQ, 非持久消息不不会送到DLQ。本 文将展示如何在Spring中引 入私信重发机制。

在这里插入图片描述

2、死信的产生原因

1.死信队列列堆积过多

测试的时候,每秒50条消息,堆积到3000 以上的时候,就会不不定时地报错

在这里插入图片描述

因为每次连接MQ的时候,都创建了了连接对象,占 用内存太多,建议使 用连接池,修改Spring 的配置

在这里插入图片描述

  1. 网络故障::udp通信 网络通信不不正常会出现消息丢失,或挤压状况。

3.连接超时:ActiveMQ服务器 挂了了,要搭建集群,保证高可 用。

二.Spring + ActiveMQ配置 死信队列列(重发机制/延时发送)

1.ActiveMQ 部署时修改activemq.xml

在policyEntries节点中增加如下策略略配置。
在这里插入图片描述

2.服务端spring-mq配置 文件做如下配置

<?xmlversion="1.0" encoding="UTF-8"?>

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"default-lazy-init=“true”>

brokerURL="${brokerUrl}"

userName=" m q . u s e r N a m e " p a s s w o r d = " {mq.userName}"password=" mq.userName"password="{mq.password}"

redeliveryPolicy=“activeMQPolicy”/>–>

<bean id=“amqConnectionFactory”

class=“org.apache.activemq.ActiveMQConnectionFactory”>

<!-- 引

用重发机制 -->

class=“org.springframework.jms.connection.CachingConnectionFactory”> <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的

ConnectionFactory -->
<property name=“targetConnectionFactory”

ref=“amqConnectionFactory”>

<bean id=“allDestination”

class=“org.apache.activemq.command.ActiveMQQueue”> <constructor-argvalue=“C2S.Q.TEST” />

<bean id=“listenerContainer”

class=“org.springframework.jms.listener.DefaultMessageListenerContainer”>

<!–dataReceiver

为MQ处理理类,根据实际情况配置–>


3、ActiveMQ配置死信队列列(丢弃机制)

需求场景:

由于测试环境应 用复杂的原因,造成了了jms死信队列列 一直挤压很多数据,从 而导致存储爆满,进 而造成了了各个客户端不不能正常发送消息。针对这些死信队列列,一般都没有利利 用价值的。

为了了避免某队列列的死信队列列的挤压,而使整个jms不不可 用,我们选择了了通过ActiveMQ的配置,直接丢弃掉死信队列列的消息。缺省死信队列列(Dead Letter Queue)叫做ActiveMQ.DLQ所有的未送达消息都会被发送到这个队列列,以致会非常难于管理理。

所以我们为了了防 止内存挤压导致mq不不可 用的情况发 生,就需要对死信进 行行配置。可以通过配置文件(activemq.xml)来调整死信发送策略略。

一些配置策略略:

1. 不不使用缺省的死信队列列 缺省所有队列列的死信消息都被发送到同 一个缺省死信队列列,不不便便于管理理。

可以通过individualDeadLetterStrategy或sharedDeadLetterStrategy策略略来进 行行修改。如下:
在这里插入图片描述

useQueueForQueueMessages: 设置使 用队列列保存死信,还可以设置useQueueForTopicMessages,使 用Topic来保存死信

–>

<individualDeadLetterStrategy queuePrefix=“DLQ.”

useQueueForQueueMessages=“true” />

2. 非持久消息保存到死信队列

在这里插入图片描述

3. 过期消息不保存到死信队列

在这里插入图片描述

4. 持久消息不不保存到死信队列列

对于过期的,可以通过processExpired属性来控制,对于redelivered的失败的消息,需要通过插件来实现如下:

1)丢弃所有死信
在这里插入图片描述

2)丢弃指定 目的死信

<broker …>

注意, 目的名称使 用空格分隔
  1. 用正则表达式过滤丢弃消息

在这里插入图片描述

4、死信队列列消息的属性

死信队列列中的消息,会增加 几个属性, 比如原过期时间(originalExpiration),原originalDeliveryMode等。

五.死信队列列解决方案总结

1.重发:对于安全性要求比较高的系统,那需要将发送失败的消息进行重试发送,甚至在消息一直不能到达的情况下给予相关的邮件、短信等必要的告警措施以保证消息的正确投递。

2.丢弃:在消息不是很重要以及有其他通知手段的情况下,那么对消息做丢弃处理也不失为一种好办法,毕竟如果大量不可抵达的消息存在于消息系统中会对我们的系统造成非常大的负荷,所以我们也会采用丢弃的方式进行处理。

3.不管是 重发还是丢弃,都要根据实际的业务场景而定,不一而足,同志们在实际中要具体问题具体分析。

  • 16
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安装和配置ActiveMQ,请按照以下步骤进行操作: 1. 下载安装包:访问ActiveMQ官方网站(http://activemq.apache.org/components/classic/download/),根据您的操作系统选择合适的版本进行下载。 2. 解压缩安装包:将下载的安装包解压到您选择的目录。 3. 启动ActiveMQ:进入解压后的目录中的bin/win64目录,找到activemq.bat文件,双击运行或在命令行中执行此文件。 4. 配置ActiveMQ:启动成功后,您可以使用命令行窗口打开活动MQ管理控制台。在浏览器中输入http://localhost:8161,进入管理页面。 5. 配置队列和主题:在管理页面中,您可以创建和配置队列和主题以满足您的需求。通过添加新的队列和主题来实现消息传递和发布/订阅模式。 6. 测试与使用:您现在可以使用ActiveMQ来发送和接收消息。您可以使用ActiveMQ的Java API或其他客户端库来编写代码并与ActiveMQ进行通信。 请注意,这只是一个简单的概述,您可能需要参考ActiveMQ的官方文档或其他资源以获取更详细的安装和配置说明。希望这些步骤能帮助您成功安装和配置ActiveMQ。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [ActiveMQ安装使用](https://blog.csdn.net/qq_29651203/article/details/108487924)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [ActiveMQ安装使用与配置说明](https://blog.csdn.net/zgphacker2010/article/details/127140614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值