ActiveMQ----->如何保证消息可靠性

一 持久化

1.1 API设置

java默认是持久化的

1.2 Topic持久化

默认情况下,topic发布时,如果订阅者不在线。消息就会丢失

但我们可以用持久化Topic来解决这个问题。

先启动订阅在启动生产

生产者

public class TopicProducer {
    public static final String ACTIVE_URL = "tcp://192.168.6.10:61616";
    public static final String TOPIC_NAME = "topic01";
 
    public static void main(String[] args) throws JMSException {
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVE_URL);
        Connection connection = activeMQConnectionFactory.createConnection();
 
        Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
        Topic topic = session.createTopic(TOPIC_NAME);
 
        MessageProducer producer = session.createProducer(topic);
        //与之前的实现没有区别,只是将消息设置为持久化后再开始连接即可
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        connection.start();
        for (int i = 0; i < 3; i++) {
            TextMessage textMessage = session.createTextMessage("msg---" + i);
            producer.send(textMessage);
        }
 
        producer.close();
        session.close();
        connection.close();
        System.out.println("发送持久化topic完成~");
 
    }
}

订阅者

public class TopicConsumer {
    public static final String ACTIVE_URL = "tcp://192.168.6.10:61616";
    public static final String TOPIC_NAME = "topic01";
    
    public static void main(String[] args) throws JMSException {
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVE_URL);
        Connection connection = activeMQConnectionFactory.createConnection();
        //要设置一个订阅该主题的订阅者Id
        connection.setClientID("ww");
        Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
        Topic topic = session.createTopic(TOPIC_NAME);
        //这里与之前不同,要通过session创建一个持久化的订阅者
        //参数为订阅的主题与备注
        TopicSubscriber t = session.createDurableSubscriber(topic, "我是ww");
        connection.start();
        //阻塞式接收消息
        Message message = t.receive();
 
        while(message != null){
            TextMessage textMessage = (TextMessage) message;
            System.out.println("收到的持久化topic :"+textMessage.getText());
            message = t.receive();
        }
 
 
    }
 
}

二 事务

事务偏生产者

2.1 生产者事务

事务的配置优先度高于应答模式(签收)

		//第一个参数是是否创建session,第二个参数表示应答模式
        Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);

不开启事务时
只要执行send就进入到队列中

开启事务后
需要在最后使用session.commit();,某一条异常也可以用session.rollback();

2.2 消费者事务

不开启事务时
消息拿到就算作被消费了

开启事务时
没有commit,消息就不会算作被消费。会有重复消费的可能

事务开启的意义在于,如果对于多条必须同批次传输的消息,可以使用事务,如果一条传输失败,可以将事务回滚,再次传输,保证数据的完整性

1)对于生产者来说

消息生产者偏重于事务,开启事务后send的消息,只有在session执行commit后才会被提交到服务器,不然无效。

2)对于消费者来说

消费者偏重于签收,但开启事务后,消息是否被消费就只和是否commit有关了,消息在commit后会自动签收,如回滚,则消息会被继续传送,如不开启事务,则需要通过签收来进行消息的消费(下文会提到)
 

三 签收

签收偏消费者

3.1 非事务模式

自动签收(默认)

Session.AUTO_ACKNOWLEDGE

手动签收

Session.CLIENT_ACKNOWLEDGE
客户端调用acknowledge方法手动签收

签收一般会在非事务状态下生效,且主要针对于消费者,生产者的签收功能并没有什么意义,因为如果开启事务的话,签收与否取决于是否提交和回滚。

签收一共有四种状态,最常用的签收状态有两种.

在非事务状态下,如果设置了手动签收,那必须在recieve到一条消息后进行签收,不然消息仍然是未被消费的状态,下次消费时依旧能获取到没被签收的消息。

允许重复消息


Session.DUPS_OK_ACKNOWLEDGE

消息可重复确认,意思是此模式下,可能会出现重复消息,并不是一条消息需要发送多次ACK才行。它是一种潜在的"AUTO_ACK"确认机制,为批量确认而生,而且具有“延迟”确认的特点。对于开发者而言,这种模式下的代码结构和AUTO_ACKNOWLEDGE一样,不需要像CLIENT_ACKNOWLEDGE那样调用acknowledge()方法来确认消息。

 事务模式下
消费者事务开启,只有commit后才能将全部消息变为已消费,写ack没有作用,即使写了签收也不会签收出队

 和事务的联系
在事务性会话中,当一个事务被成功提交则消息被自动签收。如果事务回滚,则消息会被再次传送
非事务会话中,消息何时被确认取决于创建会话时的应答模式(acknowledgement)
 

总结:在ActiveMQ保证消息可靠性的四种方式

1)进行消息的持久化:queue默认为持久化,topic模式下需要手动设置

2)开启消息的事务

3)在消费者的非事务状态下要开启消息手动签收功能

4)集群搭建实现高可用

猜你喜欢

转载自blog.csdn.net/m0_46405589/article/details/115078495