(三) ActiveMQ的可靠性(持久化、事务与签收) 与 Broker

ActiveMQ的可靠性

ActiveMQ的可靠性我们主要从一下三点分析

  • PERSISTENT: 持久化
  • Transacted: 事务
  • Acknowkedge: 签收

持久化

持久化可以在创建生产者之后开启:
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);

看一下DeliveryMode的源码,来了解setDeliveryMode的参数。

package javax.jms;

public interface DeliveryMode {
    
    
	//非持久化
    static final int NON_PERSISTENT = 1;	
	//持久化
    static final int PERSISTENT = 2;
}
  1. 参数设置说明:
  • 持久:当服务器宕机,消息依然存在。
    messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);

  • 非持久:当服务器宕机,消息不存在
    messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

  1. 持久的Queue
    默认为持久化。持久化消息,这是队列的默认传送方式,此模式保证这些消息只被传送一次和成功使用一次。对于这些消息,可靠性是优先考虑的因素。

    可以去测试一下,发布的消息,经历过MQ服务器的重启之后消息仍然存在。

    可靠性的另一个重要方面是确保持久性消息传送志目标后,消息服务在向消费者传送他们之前不会丢失这些消息。

  2. 持久的Topic
    持久订阅

    1. 一定要先运行一次消费者,等于向MQ注册,类似于我订阅了这个主题
    2. 然后再运行生产者发送消息
    3. 此时无论消费者是否在线,都会接收到。不在线的话,下次连接的时候,会把没有收过的消息都接收下来。

需要生产者设置持久化:
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
消费者创建订阅:
TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic, "remark...");

客户端首先向MQ注册以恶搞自己的身份ID识别号,当这个客户端处于离线时,生产者会为这个ID保存所有发送到主题的消息,当客户端再次连接到MQ时会根据消费者的ID得到所有当自己处于离线时发送到主题的消息。

非持久订阅状态下,不能恢复或重新派送一个未签收的消息。
持久订阅才能恢复或者重新派送一个未签收的消息。

测试一下持久化订阅

public static final String ACTIVEMQ_URL = "tcp://129.*.*.*:61616";
	public static final String TOPIC_NAME = "topic02";

	public static void main(String[] args) throws Exception {
    
    

		System.out.println("*****t2");
		
		// 创建连接工厂
		ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
		// 创建连接Connection
		Connection connection = connectionFactory.createConnection();
		connection.setClientID("t2");
		
		// 创建会话Session
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		// 创建目的地
		Topic topic = session.createTopic(TOPIC_NAME);
		
		//创建订阅
		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();

	}

首先启动两个消费者来创建两个订阅。
在这里插入图片描述在这里插入图片描述在这里插入图片描述如图可以看到 t1、t2两个活跃状态的订阅。

现在先启动一下生产者,来发布几条消息。

public static final String ACTIVEMQ_URL = "tcp://129.*.*.*:61616";
	public static final String TOPIC_NAME = "topic02";
	
	public static void main(String[] args) throws Exception {
    
    
		//1 创建连接工厂
		ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
		
		//2 通过连接工厂,获得连接connection并启动访问
		Connection connection = activeMQConnectionFactory.createConnection("admin", "admin");
		
		
		//3 创建会话Session
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		
		//4 创建目的地
		Topic topic = session.createTopic(TOPIC_NAME);
		
		//5 创建消息生产者
		MessageProducer messageProducer = session.createProducer(topic);
		
		//持久化
		messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
		
		//启动
		connection.start();
		
		//6 通过使用messageProducer生产消息发送到topic主题
		for(int i=0;i<3;i++) {
    
    
			//7 创建消息
			TextMessage textMessage = session.createTextMessage("Topic_Name:"+i);
			
			//8 通过messageProducer发送给mq
			messageProducer.send(textMessage);
		}
		//9 关闭资源
		messageProducer.close();
		session.close();
		connection.close();
		
		
		System.out.println("******TOPIC_NAME消息发布到MQ完成*************");
	}

查看一下运行结果:
在这里插入图片描述在这里插入图片描述在这里插入图片描述发现 t1、t2两个订阅者都收到了发出的三条消息。

现在关闭 t1 、 t2 两位订阅者。
在这里插入图片描述发现 t1 、t2 两位订阅者处于离线状态,但服务器还保留着他们的记录。

现在重新启动生产者,继续发送三条消息。
在这里插入图片描述t1、t2 两个订阅者虽然处于离线,但是topic02 仍然显示又两个消费者。
现在重新启动 t1 、t2 两位订阅者,看看他们能否接收到消息。
在这里插入图片描述在这里插入图片描述t1 和 t2 虽然关闭,然是服务端他们都处于离线状态,在此期间如果有持久化消息发送。等到他们重新连接上的时候,就可以接收到消息。

事务

事务是在创建session的时候选择是否开启。connection.createSession方法的第一个参数为 true 则开启事务。
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

需在session关闭之前手动提交.session.commit();

try{
    
    
	//ok 
	session.commit();//提交
}catch(Exception e){
    
    
	//printStackTrace()
	//error
	Session.rollback();	//回滚
}finally{
    
    
	if(null!=session){
    
    
	session.close();
	}
}

生产者中开启事务,session.commit()提交之后发布的消息才会入队。
消费者中开启事务,session.commit()提交之后消费的消息才会出队。

签收

签收是在创建session的时候选择是否开启。connection.createSession方法的第一个参数为 true 则开启事务。
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

  • 非事务
    自动签收:Session.AUTO_ACKNOWLEDGE
    手动签收:Session.CLIENT_ACKNOWLEDGE
    允许重复消息:Session.DUPS_OK_ACKNOWLEDGE

//手动签收
message.acknowledge();
客户端调用acknowledge方法手动签收。
如不签收,消息不会出队。

  • 事务
    开启事务,手动签收模式。
    只有session.commit()才能将消费的消息出队,
    没有session.commit(),采用message.acknowledge()并不能让消息出队,造成重复消费。
  • 签收和事务的关系
    事务要比签收大,开启事务,必须用session.commit()

ActiveMQ的Broker

  • 是什么?
    相当于一个ActiveMQ服务器实例。

    Broker其实就是实现了用代码的形式启动ActiveMQ将MQ嵌入到Java代码中,以便随时用随时启动。

    在用的时候再去启动这样就能节省了资源,也保证了可靠性。
    就好比以前访问的是Linux下的MQ, 现在用代码整一个小型的,访问代码即可。

  • 嵌入式Broker
    用ActiveMQ Broker 作为独立的消息服务器来构建Java应用。
    ActiveMQ也支持在VM中通信基于嵌入式的broker,能够无缝的集成其他Java应用。

    引入Jar包

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.11.3</version>
</dependency>

activemq关闭状态
在这里插入图片描述
启动如下代码

public static void main(String[] args) throws Exception {
    
    
		//ActiveMQ也支持在VM中通信基于嵌入式的broker,能够无缝的集成其他Java应用。
		BrokerService brokerService = new BrokerService();
		brokerService.setUseJmx(true);
		brokerService.addConnector("tcp://localhost:61616");
		brokerService.start();
	}

现在这个微型的MQ服务器就已经启动了。
在这里插入图片描述将我们之前的生产者与消费者中的代码 ACTIVEMQ_URL替换。
public static final String ACTIVEMQ_URL = "tcp://localhost:61616";

尝试运行
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Zhangxg0206/article/details/109775813
今日推荐