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;
}
- 参数设置说明:
-
持久:当服务器宕机,消息依然存在。
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
-
非持久:当服务器宕机,消息不存在
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
-
持久的Queue
默认为持久化。持久化消息,这是队列的默认传送方式,此模式保证这些消息只被传送一次和成功使用一次。对于这些消息,可靠性是优先考虑的因素。可以去测试一下,发布的消息,经历过MQ服务器的重启之后消息仍然存在。
可靠性的另一个重要方面是确保持久性消息传送志目标后,消息服务在向消费者传送他们之前不会丢失这些消息。
-
持久的Topic
持久订阅- 一定要先运行一次消费者,等于向MQ注册,类似于我订阅了这个主题
- 然后再运行生产者发送消息
- 此时无论消费者是否在线,都会接收到。不在线的话,下次连接的时候,会把没有收过的消息都接收下来。
需要生产者设置持久化:
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";
尝试运行