spring rabbitmq 消息确认机制和事务支持

转载 2016年09月05日 17:35:49

确认并且保证消息被送达,提供了两种方式:发布确认和事务。(两者不可同时使用)在channel为事务时,不可引入确认模式;同样channel为确认模式下,不可使用事务。

发布确认:
Confirms给客户端一种轻量级的方式,能够跟踪哪些消息被broker处理,哪些可能因为broker宕掉或者网络失败的情况而重新发布。
确认消息是否到达broker服务器,也就是只确认是否正确到达exchange中即可,只要正确的到达exchange中,broker即可确认该消息返回给客户端ack。
有两种方式:消息的确认和消息发送失败的回调。
消息确认:
在配置connectionFactory 中启用消息确认:

    <bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">  
        <property name="host" value="${rabbitmq.host}" />  
        <property name="port" value="${rabbitmq.port}" />  
        <property name="username" value="${rabbitmq.username}" />  
        <property name="password" value="${rabbitmq.password}" />  
        <property name="virtualHost" value="${rabbitmq.virtualHost}" />
        <!-- 缓存模式   CONNECTION CHANNEL,默认的缓存模式是CHANNEL。
        当缓存模式是 CONNECTION时, 队列的自动声明等等 (参考 the section called “Automatic Declaration of Exchanges, Queues and Bindings”) 将不再支持。
        在框架(如. RabbitTemplate) 中使用的通道将会可靠地返回到缓存中.如果在框架外创建了通道 (如.直接访问connection(s)并调用 createChannel() ),
        你必须可靠地返回它们(通过关闭),也许需要在 finally 块中以防止耗尽通道.
         -->
        <property name="cacheMode" value="CHANNEL"/>
        <!-- 默认通道缓存25,多线程环境中,较小的缓存意味着通道的创建和关闭将以很高的速率运行.加大默认缓存大小可避免这种开销
         如果达到了限制,调用线程将会阻塞,直到某个通道可用或者超时, 在后者的情况中,将抛出 AmqpTimeoutException异常.-->
        <property name="channelCacheSize" value="10"/>
        <!-- channelCheckoutTimeout属性. 当此属性的值大于0时, channelCacheSize会变成连接上创建通道数目的限制. -->
        <property name="channelCheckoutTimeout" value="200"/>
        <!-- 发布确认必须配置在CachingConnectionFactory上 -->
        <property name="publisherConfirms" value="true"/>
    </bean>
模板配置消息确认回调方法:

    <bean id="confirmCallback" class="com.convict.rabbitmq.spring.sync.callback.MsgSendConfirmCallBack"/>
    <!-- 同步访问rabbitmq-->
    <bean id="rabbitTemplate"  class="org.springframework.amqp.rabbit.core.RabbitTemplate">  
        <constructor-arg name="connectionFactory" ref="connectionFactory"/>
        <property name="exchange" value="${rabbitmq.exchangeName}"/>
        <!-- 也可以在发送的时候手动设置routing key -->
        <property name="routingKey" value="${rabbitmq.msg.routing}"/>
		
        <!--消息确认回调 -->
        <property name="confirmCallback" ref="confirmCallback"/>
    </bean>

MsgSendConfirmCallBack 代码如下:

    public class MsgSendConfirmCallBack implements RabbitTemplate.ConfirmCallback {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            if (ack) {
                System.out.println("消息确认成功");
            } else {
                //处理丢失的消息
                System.out.println("消息确认失败,"+cause);
            }
        }
    }


消息发送失败回调:

CachingConnectionFactory配置中启用回调
<property name="publisherReturns" value="true"/>
定义回调方法,并在消息模板中指定

<bean id="sendReturnCallback" class="com.convict.rabbitmq.spring.sync.callback.MsgSendReturnCallback"/>
	<bean id="rabbitTemplate"  class="org.springframework.amqp.rabbit.core.RabbitTemplate">  
        <constructor-arg name="connectionFactory" ref="connectionFactory"/>
        <property name="exchange" value="${rabbitmq.exchangeName}"/>
        <!-- 也可以在发送的时候手动设置routing key -->
        <property name="routingKey" value="${rabbitmq.msg.routing}"/>
        <property name="returnCallback" ref="sendReturnCallback"/>
    </bean>
MsgSendReturnCallback 方法如下:
	public class MsgSendReturnCallback implements RabbitTemplate.ReturnCallback {
		@Override
		public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
			String msgJson  = new String(message.getBody());
			System.out.println("Returned Message:"+msgJson);
		}
	}

事务
Spring AMQP做的不仅仅是回滚事务,而且可以手动拒绝消息,如当监听容器发生异常时是否重新入队。
持久化的消息是应该在broker重启前都有效。如果在消息有机会写入到磁盘之前broker宕掉,消息仍然会丢失。在某些情况下,这是不够的,发布者需要知道消息是否处理正确。简单的解决方案是使用事务,即提交每条消息。

使用事务有两个问题:
一、会阻塞,发布者必须等待broker处理每个消息。如果发布者知道在broker死掉之前哪些消息没有被处理就足够了。
二、事务是重量级的,每次提交都需要fsync(),需要耗费大量的时间。
confirm模式下,broker将会确认消息并处理。这种模式下是异步的,生产者可以流水式的发布而不用等待broker,broker可以批量的往磁盘写入。

场景:业务处理伴随消息的发送,业务处理失败(事物回滚)后要求消息不发送。rabbitmq 使用调用者的外部事物。
示例:使用spring事物,来处理业务并发送消息,并且把消息记录到数据库中防止消息的丢失。
代码说明:
1、rabbitTemplate 使用外部事物配置
    <!-- 同步访问rabbitmq-->
    <bean id="rabbitTemplate"  class="org.springframework.amqp.rabbit.core.RabbitTemplate">  
        <constructor-arg name="connectionFactory" ref="connectionFactory"/>
        <property name="exchange" value="${rabbitmq.exchangeName}"/>
        <!-- 也可以在发送的时候手动设置routing key -->
        <property name="routingKey" value="${rabbitmq.msg.routing}"/>
        <!-- 使用外部事物 -->
        <property name="channelTransacted" value="true"/>
    </bean>
2、创建消息表 CREATE TABLE tb_msg(id BIGINT,tag INT,txt TEXT); 使用 spring-mybatis 搭建表的操作,配置事物。
3、模拟 MsgService 中业务处理方法如下(事物切面在service层):
public void addMsg(Msg msg) throws Exception {
        //模拟业务操作
        Thread.sleep(1000);
        //消息保存到数据库,和业务操作为同一个事物
        msgDao.insert(msg);
		
        //发送消息
        rabbitTemplate.convertAndSend(msg.getTxt());
        if (msg.getId() == null || msg.getId() % 2 == 0) {//事物,偶数的回滚
            throw new Exception();
        }
    }

当事物回滚,消息也不会发送。

注意:一个具有事务的channel不能放入到确认模式,同样确认模式下的channel不能用事务。

完整code:http://download.csdn.net/detail/convict_eva/9625428

参考:http://my.oschina.net/lzhaoqiang/blog/670749

相关文章推荐

RabbitMQ之消息确认机制(事务+Confirm)

概述在使用RabbitMQ的时候,我们可以通过消息持久化操作来解决因为服务器的异常奔溃导致的消息丢失,除此之外我们还会遇到一个问题,当消息的发布者在将消息发送出去之后,消息到底有没有正确到达broke...

分布式消息队列RocketMQ--事务消息--解决分布式事务的最佳实践

说到分布式事务,就会谈到那个经典的”账号转账”问题:2个账号,分布处于2个不同的DB,或者说2个不同的子系统里面,A要扣钱,B要加钱,如何保证原子性?一般的思路都是通过消息中间件来实现“最终一致性”:...

rabbitmq丢消息的处理方法

最近发现系统rabbitmq丢消息比较严重,于是想了些方案来查找原因,给将消息发送方式添加确认机制。   我们在本地模拟了wms发送打标消息的场景. 1. 有事务 2. 先发点对点队列, 再发...

rabbitmq的发布确认和事务

转:https://my.oschina.net/lzhaoqiang/blog/670749 摘要: 介绍confirm的工作机制。使用spring-amqp介绍事务以及发布确认的使用方式。因为事...

RabbitMQ(三)RabbitMQ消息过期时间(TTL)

在RabbitMQ(二)AMQP协议mandatory和immediate标志位区别中我们提到,在RabbitMQ3.0以后的版本里,去掉了immediate参数支持,要实现类似的确认功能要使用TTL...
  • xtjsxtj
  • xtjsxtj
  • 2014年03月25日 13:56
  • 10050

SpringBoot的RabbitMQ消息队列: 三、第二模式"Work queues"

上一节的两个工程,一个负责发送,一个负责接收,也就是一一对于的关系。      只要消息发出了,接收者就处理;当接收效率较低时,就会出现接收者处理不过来,我们就可能会处理不过来,于是我们就可能多配置接...
  • lxhjh
  • lxhjh
  • 2017年04月04日 02:05
  • 1734

springboot(八):RabbitMQ详解

RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将RocketMQ捐献给了...

spring boot实战(第十二篇)整合RabbitMQ

前言 本篇主要讲述Spring Boot与RabbitMQ的整合,内容非常简单,纯API的调用操作。  消息生产者 不论是创建消息消费者或生产者都需要ConnectionFactory C...

RabbitMQ(四)消息确认(发送确认,接收确认)

前面几篇记录了收发消息的demo,今天记录下关于 消息确认方面的 问题. 下面是几个问题: 1.为什么要进行消息确认? 2.rabbitmq消息确认 机制是什么样的? 3.发送方如何确认消息发送成功?...

AmqpTemplate-发送-接收-消息

AmqpTemplate-简介     就像Spring Framework和其它一些项目提供了一些高度抽象,Spring AMQP提供的‘template’扮演者关键的角色。定义者...
  • sn_gis
  • sn_gis
  • 2014年11月17日 12:40
  • 6315
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:spring rabbitmq 消息确认机制和事务支持
举报原因:
原因补充:

(最多只允许输入30个字)