activeMq消息队列的可靠化使用
消息队列的可靠化使用需要了解消息队列的机制,如持久化和重试机制,只要理解了该机制,可靠化使用就变得非常容易了。不扯了,上干货。
activeMq消息持久化
`在activeMq的使用中,依据所以用的jms框架(但一般不进行持久化)进行持久化操作,否则会出现activeMq宕机后消息消失的情况,这是,持久化的作用就展示出来了。设置持久化需要在消息生产者方设置消息持久化(代码为producer.setDeliveryMode(DeliveryMode.PERSISTENT);)
static public void start() throws JMSException {
System.out.println("生产者已经启动....");
// 创建ActiveMQConnectionFactory 会话工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, BROKERURL);
Connection connection = activeMQConnectionFactory.createConnection();
// 启动JMS 连接
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(null);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);//设置消息持久化
send(producer, session);
System.out.println("发送成功!");
connection.close();
}
ActiveMQ消息签收机制
客戶端成功接收一条消息的标志是一条消息被签收,成功应答。
1、带事务的session
如果session带有事务,并且事务成功提交,则消息被自动签收。如果事务回滚,则消息会被再次传送。
2、不带事务的session
不带事务的session的签收方式,取决于session的配置。
Activemq支持一下三種模式:
1.消息自动签收
Session.AUTO_ACKNOWLEDGE 消息自动签收(消息发送方设置)
2.消息手动签收
Session.CLIENT_ACKNOWLEDGE 消息手动签收(消息发送方设置)
textMessage.acknowledge();//手动签收(消息接收方提交签收消息)
3.不是必须签收
Session.DUPS_OK_ACKNOWLEDGE 不是必须签收,消息可能会重复发 送。在第二次重新传送消息的时候,消息只有在被确认之后,才认为已经被成功地消费了
场景1
生产者不开启session,客户端必须有手动签收模式
Session session = createConnection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);
消费者不开启session,客户端必须有手动签收模式
TextMessage textMessage = (TextMessage) createConsumer.receive();
//接受消息
textMessage.acknowledge();
场景2
生产者不开启session,客户端自动签收模式
Session session = createConnection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
消费者不开启session,自动签收消息
Session session = createConnection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
场景3
事物消息 生产者以事物形式,必须要将消息提交事物,才可以提交到队列中。
Session session = createConnection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
session.commit();
消费者
Session session = createConnection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
session.commit();
消息自动签收
在自动签收情况下消息消费方出现异常,activeMq默认自动进行重试。
@JmsListener(destination = "${queue}")
public void receive(String textMessage) {
try {
System.out.println("消费端接受到生长者消息: " + textMessage+ " 第几次获取消息 count:" + (++count));
int i = 1 / 0;//在这里发生异常会一直进行重试 此时不要进行重试
}catch(Excetpion e){
//此时需要在这里进行补偿机制
//采用方案 (人工补偿、定时job健康检查、异常日志记录)等方案
}
}
消息手动签收 (实际项目中采用的方式)
在手动签收模式下,因为网络延迟的问题,消费者没有进行消费信息提交,activemq会进行重试,此时会产生重复消费的问题(幂等性问题)可以使用全局id进行处理,也可以使用业务逻辑id进行处理(一般使用消息id)
@JmsListener(destination = "${queue}")
public void receive(TextMessage textMessage,Session session) {
try {
String text = textMessage.getText();
System.out.println("消费端接受到生长者消息: " + text + " 第几次获取消息 count:" + (++count));
int i = 1 / 0;
//伪代码耗时15秒 模拟网络延迟情况(会进行自动重试)
Thread.sleep(15000l);
String jmsMessageID = textMessage.getJMSMessageID();
//网络延迟情况下,第二次消费过来,应该使用全局ID该消息是否被消费。
// if(jmsMessageID==缓存里面){
// textMessage.acknowledge();// 消息提交 }
// 消費成功
//jmsMessageID==存放在緩存裡面
} catch (Exception e) {
// 在 catch 日志记录消息报文,可以采用补偿机制 (使用人工补偿),使用定时JOB健康检查脏数据。
// session.recover();// 手动重试。
}
}
总结
activemq的可靠化使用也就是采用手动消息提交和消息持久化即可实现消息队列的可靠化使用。手动消息提交需要解决消息队列的幂等性问题(请看上面的解决方案)。如果消息队列(消费者)集群的情况下不需要考虑幂等性问题,mq集群的问题下需要解决幂等性问题。幂等性问题产生原因:网络延迟和消息队列的重试机制。