rabbitmq生产者消息确认机制

青春壹個敷衍的年華 提交于 2020-08-14 11:25:46

rabbitmq生产者消息确认机制

问题描述

当生产者发送消息给rabbitmq服务器时,消息是否真正的到达了服务器?为了保证生产者发送的消息能够可靠的发送到服务器(即消息落地),rabbitmq提供了两种方式:

  • 通过事务实现
  • 通过发送方确认机制(publisher confirm)实现

事务机制

rabbitmq与事务相关的方法:

  • channel.txSelect(): 将当前信道设置成事务模式
  • channel.txCommit(): 用于提交事务
  • channel.txRollback(): 用于回滚事务

通过事务实现机制,只有消息成功被rabbitmq服务器接收,事务才能提交成功,否则便可在捕获异常之后进行回滚,然后进行消息重发,但是事务非常影响rabbitmq的性能。还有就是事务机制是阻塞的过程,只有等待服务器回应之后才会处理下一条消息

示例:

public class TransactionSender {


    private static final String ex_name = "ex_tx";
    private static final String q_name = "q_tx";
    private static final String rt_name = "rt_tx";

    public static void main(String[] args) throws IOException, TimeoutException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare(ex_name, BuiltinExchangeType.DIRECT);
        channel.queueDeclare(q_name, false, false, false, null);
        channel.queueBind(q_name, ex_name, rt_name);

        channel.txSelect();
        try {
            channel.basicPublish(ex_name, rt_name, null, "hello".getBytes());
            //显示抛出RuntimeException
            int a = 1/0;
            channel.txCommit();
        } catch (IOException e) {
            e.printStackTrace();
            channel.txRollback();
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

通过Web管理台可以发现,消息并没有发到到相对应的队列中去

发送方确认机制

发送方确认机制分为同步和异步

原理

生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的id(从1开始),一旦消息被投递到匹配的队列之后,rabbitmq就会发送一个确认(Basic.Ack)和deliverTag(消息id)给生产者。如果消息和队列是持久化的那么消息会在持久化之后被发出。rabbitmq除了回传deliverTag之外,还有multiple参数,表示到这个序号之前所有的消息都得到了处理。所有的消息只会被AckNack一次,不会出现既被Ack又被Nack

同步确认

同步确认:

public class SyncConfirmSender {

    private static final String ex_name = "ex_confirm";
    private static final String q_name = "q_confirm";
    private static final String rt_name = "rt_confirm";


    public static void main(String[] args) throws IOException, TimeoutException,
    						 InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare(ex_name, BuiltinExchangeType.DIRECT);
        channel.queueDeclare(q_name, false, false, false, null);
        channel.queueBind(q_name, ex_name, rt_name);

        //将信道设置成确认模式
        channel.confirmSelect();
        channel.basicPublish(ex_name, rt_name, null, "hello".getBytes());
        //同步确认
       if (!channel.waitForConfirms()){
           System.out.println("发送失败...");
       }else {
           System.out.println("发送成功...");
       }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

异步确认

异步确认:

public class SyncConfirmSender {

    private static final String ex_name = "ex_confirm";
    private static final String q_name = "q_confirm";
    private static final String rt_name = "rt_confirm";


    public static void main(String[] args) throws IOException, TimeoutException, 
    							InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare(ex_name, BuiltinExchangeType.DIRECT);
        channel.queueDeclare(q_name, false, false, false, null);
        channel.queueBind(q_name, ex_name, rt_name);

        channel.confirmSelect();
        //添加监听器
        channel.addConfirmListener(new ConfirmListener() {
            @Override
            public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                System.out.println("Ack: tag no: "+ deliveryTag+ " multiple: "+ multiple);
            }

            @Override
            public void handleNack(long deliveryTag, boolean multiple) throws IOException {
                System.out.println("Nack: tag no: "+ deliveryTag+ " multiple: "+ multiple);

            }
        });
        channel.basicPublish(ex_name, rt_name, null, "hello".getBytes());
    }

}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!