ActiveMQ 可靠性保障:消息确认与重发机制(一)

引言

{"type":"load_by_key","key":"auto_image_0_0","image_type":"search"}

在当今分布式系统的架构中,消息中间件扮演着举足轻重的角色,而 ActiveMQ 作为一款广泛使用的开源消息中间件,凭借其对 JMS(Java Message Service)规范的支持、多种消息传输协议、丰富的消息模型(如点对点和发布 / 订阅)以及出色的集群能力 ,成为众多开发者构建分布式系统的重要选择。在分布式系统中,消息的可靠传输至关重要,哪怕是偶尔出现的消息丢失或处理失败,都可能引发系统功能的异常,给业务带来严重影响。

为了确保消息能准确无误地被处理,ActiveMQ 引入了消息确认与重发机制。消息确认机制让生产者或消费者知晓消息的处理状态,重发机制则在消息处理出现异常时重新发送消息,这两种机制共同为消息传输的可靠性提供保障。接下来,本文将深入探讨 ActiveMQ 的消息确认与重发机制,包括它们的原理、工作方式、使用场景以及相关的代码示例。

ActiveMQ 消息确认机制

确认机制的概念与作用

消息确认机制是 ActiveMQ 确保消息可靠传输的关键机制,它定义了消息发送者(生产者)或接收者(消费者)与消息代理(broker)之间确认消息已被成功处理的方式 。在消息从生产者发送到 broker,再由消费者接收的过程中,确认机制起到了至关重要的作用。

对于生产者而言,确认机制让其知晓消息是否已被 broker 成功接收并存储,从而避免因网络故障等原因导致消息丢失而生产者却不知情的情况。对于消费者来说,确认机制确保了消息在被正确处理后才被标记为已消费,防止消息的重复处理或丢失。例如,在一个订单处理系统中,生产者发送订单消息给 broker,如果没有确认机制,生产者无法确定订单消息是否成功到达 broker,可能会导致订单的重复发送或丢失,而消费者如果没有确认已成功处理订单消息,可能会在系统故障恢复后再次处理该订单,导致重复下单。

JMS 规范中的确认模式

JMS 规范定义了四种确认模式,每种模式都有其独特的工作原理、适用场景和优缺点。

  • AUTO_ACKNOWLEDGE(自动确认):当客户端成功从receive方法或onMessage方法返回时,会话会自动确认客户端已收到消息。例如,在一个简单的日志记录系统中,消费者接收到日志消息后,不需要额外的操作,消息就会被自动确认,这种模式简单易用,能提高消息处理的效率 。但它存在一定风险,如果在消息被确认后,业务处理过程中出现异常,消息已被从 broker 队列中删除,可能会导致数据不一致或业务逻辑错误。
  • CLIENT_ACKNOWLEDGE(客户端手动确认):客户端通过调用message.acknowledge()方法来手动确认消息已被接收和处理。这种模式下,确认是在会话层进行的,确认一个被消费的消息将自动确认所有已消费的其他消息。例如,在一个订单支付系统中,消费者接收到支付消息后,只有在完成支付业务逻辑并调用acknowledge()方法后,消息才会被确认,这确保了消息处理的完整性和准确性 。不过,如果开发者忘记调用acknowledge()方法,可能会导致消息一直留在 broker 队列中,占用资源,并且如果在确认前客户端出现故障,消息可能会被重复发送和处理。
  • DUPS_OK_ACKNOWLEDGE(自动批量确认):这种模式下,消息不是必须立即签收,可能会出现重复发送的情况。在第二次重新传送消息时,消息头的JmsDelivered会被置为true,标示当前消息已经传送过一次,客户端需要进行消息的重复处理控制。它适用于对消息重复不太敏感,追求高吞吐量的场景,如一些实时数据分析系统,少量的消息重复不会影响整体的分析结果,却能提高系统的处理速度 。但如果业务对消息的唯一性和准确性要求很高,这种模式就不太适用。
  • SESSION_TRANSACTED(事务提交并确认):当会话使用事务时,使用此模式。在事务开启之后,和session.commit()之前,所有消费的消息,要么全部正常确认,要么全部重新投递(redelivery)。例如,在一个涉及多个数据库操作的复杂业务场景中,将消息消费和数据库操作放在一个事务中,只有当所有数据库操作都成功完成并提交事务时,消息才会被确认,否则整个事务回滚,消息重新投递,保证了数据的一致性和完整性 。但事务的使用会增加系统的复杂性和性能开销,因为事务的管理需要额外的资源和时间。

ActiveMQ 扩展的确认模式

ActiveMQ 补充了INDIVIDUAL_ACKNOWLEDGE确认模式,用于确认单条消息。与CLIENT_ACKNOWLEDGE模式相比,CLIENT_ACKNOWLEDGE模式调用message.acknowledge()方法会确认由此会话消费的所有消息,而INDIVIDUAL_ACKNOWLEDGE模式下,仅会确认调用acknowledge()方法的那条消息 。在一个任务处理系统中,每个任务都有独立的处理逻辑和状态,如果使用CLIENT_ACKNOWLEDGE模式,可能会因为一个任务的异常导致其他任务也无法正确确认,而INDIVIDUAL_ACKNOWLEDGE模式可以精确地确认每条任务消息,即使某个任务出现问题,也不会影响其他任务的确认和处理 。不过,由于需要对每条消息进行单独确认,在消息量较大时,可能会增加系统的开销和复杂性。

确认模式的实际应用与代码示例

以下是不同确认模式下,使用 ActiveMQ 发送和接收消息的代码示例:

  • AUTO_ACKNOWLEDGE 模式
 

import javax.jms.*;

import org.apache.activemq.ActiveMQConnectionFactory;

public class AutoAcknowledgeExample {

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

// 创建连接工厂

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");

// 创建连接

Connection connection = connectionFactory.createConnection();

// 启动连接

connection.start();

// 创建会话,参数false表示不使用事务,Session.AUTO_ACKNOWLEDGE表示自动确认模式

Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// 创建队列

Destination destination = session.createQueue("testQueue");

// 创建生产者

MessageProducer producer = session.createProducer(destination);

// 创建消息

TextMessage message = session.createTextMessage("Hello, ActiveMQ!");

// 发送消息

producer.send(message);

System.out.println("Message sent: " + message.getText());

// 创建消费者

MessageConsumer consumer = session.createConsumer(destination);

// 接收消息

Message receivedMessage = consumer.receive();

if (receivedMessage instanceof TextMessage) {

TextMessage textMessage = (TextMessage) receivedMessage;

System.out.println("Received message: " + textMessage.getText());

}

// 关闭资源

consumer.close();

producer.close();

session.close();

connection.close();

}

}

在这段代码中,session.createSession(false, Session.AUTO_ACKNOWLEDGE)设置了会话的确认模式为AUTO_ACKNOWLEDGE,当消费者成功接收消息并从receive方法返回时,消息会自动被确认。

  • CLIENT_ACKNOWLEDGE 模式
 

import javax.jms.*;

import org.apache.activemq.ActiveMQConnectionFactory;

public class ClientAcknowledgeExample {

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

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");

Connection connection = connectionFactory.createConnection();

connection.start();

// 创建会话,参数false表示不使用事务,Session.CLIENT_ACKNOWLEDGE表示客户端手动确认模式

Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);

Destination destination = session.createQueue("testQueue");

MessageProducer producer = session.createProducer(destination);

TextMessage message = session.createTextMessage("Hello, ActiveMQ!");

producer.send(message);

System.out.println("Message sent: " + message.getText());

MessageConsumer consumer = session.createConsumer(destination);

Message receivedMessage = consumer.receive();

if (receivedMessage instanceof TextMessage) {

TextMessage textMessage = (TextMessage) receivedMessage;

System.out.println("Received message: " + textMessage.getText());

// 手动确认消息

receivedMessage.acknowledge();

System.out.println("Message acknowledged");

}

consumer.close();

producer.close();

session.close();

connection.close();

}

}

在这个示例中,session.createSession(false, Session.CLIENT_ACKNOWLEDGE)设置了手动确认模式,消费者在接收到消息并处理完成后,需要调用receivedMessage.acknowledge()手动确认消息。

  • INDIVIDUAL_ACKNOWLEDGE 模式(ActiveMQ 扩展)
 

import org.apache.activemq.ActiveMQConnection;

import org.apache.activemq.ActiveMQConnectionFactory;

import org.apache.activemq.ActiveMQSession;

import javax.jms.*;

public class IndividualAcknowledgeExample {

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

ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(

ActiveMQConnection.DEFAULT_USER,

ActiveMQConnection.DEFAULT_PASSWORD,

"tcp://localhost:61616");

Connection connection = connectionFactory.createConnection();

connection.start();

// 创建会话,参数false表示不使用事务,ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE表示单条消息确认模式

Session session = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE);

Destination destination = session.createQueue("testQueue");

MessageProducer producer = session.createProducer(destination);

TextMessage message = session.createTextMessage("Hello, ActiveMQ!");

producer.send(message);

System.out.println("Message sent: " + message.getText());

MessageConsumer consumer = session.createConsumer(destination);

Message receivedMessage = consumer.receive();

if (receivedMessage instanceof TextMessage) {

TextMessage textMessage = (TextMessage) receivedMessage;

System.out.println("Received message: " + textMessage.getText());

// 确认单条消息

receivedMessage.acknowledge();

System.out.println("Individual message acknowledged");

}

consumer.close();

producer.close();

session.close();

connection.close();

}

}

这段代码展示了INDIVIDUAL_ACKNOWLEDGE模式的使用,session.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE)设置了单条消息确认模式,消费者调用acknowledge()方法只会确认当前处理的这条消息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

计算机毕设定制辅导-无忧学长

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

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

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

打赏作者

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

抵扣说明:

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

余额充值