在当今分布式系统的架构中,消息中间件扮演着举足轻重的角色,而 ActiveMQ 作为一款广泛使用的开源消息中间件,凭借其对 JMS(Java Message Service)规范的支持、多种消息传输协议、丰富的消息模型(如点对点和发布 / 订阅)以及出色的集群能力 ,成为众多开发者构建分布式系统的重要选择。在分布式系统中,消息的可靠传输至关重要,哪怕是偶尔出现的消息丢失或处理失败,都可能引发系统功能的异常,给业务带来严重影响。
为了确保消息能准确无误地被处理,ActiveMQ 引入了消息确认与重发机制。消息确认机制让生产者或消费者知晓消息的处理状态,重发机制则在消息处理出现异常时重新发送消息,这两种机制共同为消息传输的可靠性提供保障。接下来,本文将深入探讨 ActiveMQ 的消息确认与重发机制,包括它们的原理、工作方式、使用场景以及相关的代码示例。
消息确认机制是 ActiveMQ 确保消息可靠传输的关键机制,它定义了消息发送者(生产者)或接收者(消费者)与消息代理(broker)之间确认消息已被成功处理的方式 。在消息从生产者发送到 broker,再由消费者接收的过程中,确认机制起到了至关重要的作用。
对于生产者而言,确认机制让其知晓消息是否已被 broker 成功接收并存储,从而避免因网络故障等原因导致消息丢失而生产者却不知情的情况。对于消费者来说,确认机制确保了消息在被正确处理后才被标记为已消费,防止消息的重复处理或丢失。例如,在一个订单处理系统中,生产者发送订单消息给 broker,如果没有确认机制,生产者无法确定订单消息是否成功到达 broker,可能会导致订单的重复发送或丢失,而消费者如果没有确认已成功处理订单消息,可能会在系统故障恢复后再次处理该订单,导致重复下单。
JMS 规范定义了四种确认模式,每种模式都有其独特的工作原理、适用场景和优缺点。
ActiveMQ 补充了INDIVIDUAL_ACKNOWLEDGE确认模式,用于确认单条消息。与CLIENT_ACKNOWLEDGE模式相比,CLIENT_ACKNOWLEDGE模式调用message.acknowledge()方法会确认由此会话消费的所有消息,而INDIVIDUAL_ACKNOWLEDGE模式下,仅会确认调用acknowledge()方法的那条消息 。在一个任务处理系统中,每个任务都有独立的处理逻辑和状态,如果使用CLIENT_ACKNOWLEDGE模式,可能会因为一个任务的异常导致其他任务也无法正确确认,而INDIVIDUAL_ACKNOWLEDGE模式可以精确地确认每条任务消息,即使某个任务出现问题,也不会影响其他任务的确认和处理 。不过,由于需要对每条消息进行单独确认,在消息量较大时,可能会增加系统的开销和复杂性。
以下是不同确认模式下,使用 ActiveMQ 发送和接收消息的代码示例:
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方法返回时,消息会自动被确认。
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()手动确认消息。
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()方法只会确认当前处理的这条消息。