rabbitmq消息可靠性

消息发送确认

https://www.jianshu.com/p/0db95a3e972c
1.事务,利用AMQP协议的一部分,发送消息前设置channel为tx模式(channel.txSelect();),如果txCommit提交成功了,则消息一定到达了broker了,如果在txCommit执行之前broker异常崩溃或者由于其他原因抛出异常,这个时候我们便可以捕获异常通过txRollback回滚事务了。(大大得削弱消息中间件的性能)
2.消息确认(publish confirms),设置管道为confirmSelect模式

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

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

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

问题:使用Spring AMQP事务有两个问题:

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


本文来自 Jamin_Ma 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/convict_eva/article/details/52442125?utm_source=copy


本文来自 Jamin_Ma 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/convict_eva/article/details/52442125?utm_source=copy

消息确认机制测试代码

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeUnit;


/**
 * @author: yangwenkang
 * @date: 2018/09/27
 * @description:
 **/

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

        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setUri("amqp://zhihao.miao:123456@192.168.1.131:5672");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();

        //第二个参数表示是否手动确认,第三参数即回调函数,具体实现消费消息后怎么处理确认消息
        //public String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException {
        String consumerTag = channel.basicConsume("zhihao.miao.order", false, new SimpleConsumer(channel));

public class SimpleConsumer extends DefaultConsumer {
    public SimpleConsumer(Channel channel) {
        super(channel);
    }
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        if (properties.getHeaders().get("error") != null) {
            try {
                TimeUnit.SECONDS.sleep(15);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //处理失败的消息,可以使用basicReject,也可使用basicNack (区别在于后者可以批量处理)
            //1 这个api也支持拒绝消息消费,第二个参数表示是否重新入队列
//          public void basicReject(long deliveryTag, boolean requeue) throws IOException {
            this.getChannel().basicReject(envelope.getDeliveryTag(), false);
            //这个api public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException {
            // this.getChannel().basicNack(envelope.getDeliveryTag(),false,false);
            return;
        }
         // 获取消息byte[] body,这里是处理消息的业务逻辑,1消费失败可以这里Nack, 2消费成功则可以backAck确认
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2 这个api也支持消费成功,ack确认消息,第二个参数表示是否批量确认
//      public void basicAck(long deliveryTag, boolean multiple) throws IOException {
        this.getChannel().basicAck(envelope.getDeliveryTag(), false);
    }
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.util.concurrent.TimeUnit;

/**
 * @author: yangwenkang
 * @date: 2018/09/27
 * @description:
 **/
public class TestRabbitMqConsumerAcknowledgement {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setUri("amqp://zhihao.miao:123456@192.168.1.131:5672");
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();

        //第二个参数表示是否手动确认,第三参数即回调函数,具体实现消费消息后怎么处理确认消息
        //public String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException {
        String consumerTag = channel.basicConsume("zhihao.miao.order", false, new SimpleConsumer(channel));

        System.out.println(consumerTag);
        TimeUnit.SECONDS.sleep(30);
        channel.close();
        connection.close();
    }

}
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeUnit;


/**
 * @author: yangwenkang
 * @date: 2018/09/27
 * @description:
 **/

public class SimpleConsumer extends DefaultConsumer {
    public SimpleConsumer(Channel channel) {
        super(channel);
    }
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        if (properties.getHeaders().get("error") != null) {
            try {
                TimeUnit.SECONDS.sleep(15);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //处理失败的消息,可以使用basicReject,也可使用basicNack (区别在于后者可以批量处理)
            //1 这个api也支持拒绝消息消费,第二个参数表示是否重新入队列
//          public void basicReject(long deliveryTag, boolean requeue) throws IOException {
            this.getChannel().basicReject(envelope.getDeliveryTag(), false);
            //这个api public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException {
            // this.getChannel().basicNack(envelope.getDeliveryTag(),false,false);
            return;
        }
         // 获取消息byte[] body,这里是处理消息的业务逻辑,1消费失败可以这里Nack, 2消费成功则可以backAck确认
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2 这个api也支持消费成功,ack确认消息,第二个参数表示是否批量确认
//      public void basicAck(long deliveryTag, boolean multiple) throws IOException {
        this.getChannel().basicAck(envelope.getDeliveryTag(), false);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值