RabbitMQ(三)发布确认 Publisher Confirms

代码仓库:github:https://github.com/stopping5/RabbitMq-Operation-Record.git

本代码示例需要引入rabbitmq依赖

      <!-- rabbitmq依赖客户端-->
       <dependency>
           <groupId>com.rabbitmq</groupId>
           <artifactId>amqp-client</artifactId>
           <version>5.8.0</version>
       </dependency>

一、什么是发布确认

Publisher confirms are a RabbitMQ extension to implement reliable publishing. When publisher confirms are enabled on a channel, messages the client publishes are confirmed asynchronously by the broker, meaning they have been taken care of on the server side.
发布订阅即使生产者发送消息到broker时,broker可以通过同步或者异步的方式通知消息生产者是否成功。

二、Channel启动消息确认

Channel channel = connection.createChannel();
channel.confirmSelect();

三、消息发布确认

1. 单条同步确认[耗性能不推荐]

/**
 * 单独确认
 * 消息发送耗时:14492ms
 * */
public static void simpleConfirmMessage() throws IOException, InterruptedException {
    Connection connection = RabbitMqUtil.getConnection();
    Channel channel = connection.createChannel();
    channel.exchangeDeclare(RabbitMQConfig.ACK_EXCHANGE, BuiltinExchangeType.DIRECT);
    //声明队列关闭了自动确认
    channel.queueDeclare(RabbitMQConfig.ACK_QUEUE,false,false,false,null);
    channel.queueBind(RabbitMQConfig.ACK_QUEUE,RabbitMQConfig.ACK_EXCHANGE,"ACK");
    //开启消息确认
    channel.confirmSelect();
    long begin = System.currentTimeMillis();
    for (int i = 0; i < PUBLISH_COUNT; i++) {
        String message = i + "";
        channel.basicPublish(RabbitMQConfig.ACK_EXCHANGE,"ACK",null,message.getBytes(StandardCharsets.UTF_8));
        boolean flag = channel.waitForConfirms();
        if (!flag){
            System.out.println("消息发送失败");
        }
    }
    long end = System.currentTimeMillis();
    System.out.println("消息发送耗时:"+(end-begin)+"ms");
}

或者可以使用Channel#waitForConfirmsOrDie(long)消息如果在限定时间内没有答复则抛出异常

Channel#waitForConfirmsOrDie(long) method. The method returns as soon as the message has been confirmed. If the message is not confirmed within the timeout or if it is nack-ed (meaning the broker could not take care of it for some reason), the method will throw an exception.

2. 批量确认同步确认

使用方式和单条发布确认一样,只不是对消息发布确认频率修改成批量确认模式,若确认失败只能知道一批消息有消息发送失败,无法精确到某一条。

/**
 * 批量发布确认
 * 批量确认消息发送耗时:268ms
 * */
public static void batchConfirmMessage() throws IOException, InterruptedException {
    Connection connection = RabbitMqUtil.getConnection();
    Channel channel = connection.createChannel();
    channel.exchangeDeclare(RabbitMQConfig.ACK_EXCHANGE, BuiltinExchangeType.DIRECT);
    //声明队列关闭了自动确认
    channel.queueDeclare(RabbitMQConfig.ACK_QUEUE,false,false,false,null);
    channel.queueBind(RabbitMQConfig.ACK_QUEUE,RabbitMQConfig.ACK_EXCHANGE,"ACK");
    //开启消息确认
    channel.confirmSelect();
    long begin = System.currentTimeMillis();
    int batchSize = 100;
    for (int i = 0; i < PUBLISH_COUNT; i++) {
        String message = i + "";
        channel.basicPublish(RabbitMQConfig.ACK_EXCHANGE,"ACK",null,message.getBytes(StandardCharsets.UTF_8));
        if (i%batchSize == 0){
            boolean flag = channel.waitForConfirms();
            if (flag){
                System.out.println("消息发送成功");
            }
        }
    }
    long end = System.currentTimeMillis();
    System.out.println("批量确认消息发送耗时:"+(end-begin)+"ms");
}

3. 异步发布确认[推荐]

相对于同步确认而言,异步确认机制新增监听器体提供确认成功和确认失败的方法,复用方法即可异步的获取到消息发送到broker的结果。

/**
 * 批量发布确认
 * 异步确认消息发送耗时:36ms
 * */
public static void asynConfirmMessage() throws IOException, InterruptedException {
    Connection connection = RabbitMqUtil.getConnection();
    Channel channel = connection.createChannel();
    channel.exchangeDeclare(RabbitMQConfig.ACK_EXCHANGE, BuiltinExchangeType.DIRECT);
    //声明队列关闭了自动确认
    channel.queueDeclare(RabbitMQConfig.ACK_QUEUE,false,false,false,null);
    channel.queueBind(RabbitMQConfig.ACK_QUEUE,RabbitMQConfig.ACK_EXCHANGE,"ACK");
    //开启消息确认
    channel.confirmSelect();
    //设置异步监听回调方法
    ConfirmCallback ackCallback = (deliveryTag,multipl)->{
        System.out.println("消息发布确认成功:"+deliveryTag);
    };
    ConfirmCallback unAckCallback = (deliveryTag,multipl)->{
        System.out.println("消息发布失败:"+deliveryTag);
    };
    channel.addConfirmListener(ackCallback,unAckCallback);
    long begin = System.currentTimeMillis();
    for (int i = 0; i < PUBLISH_COUNT; i++) {
        String message = i + "";
        channel.basicPublish(RabbitMQConfig.ACK_EXCHANGE,"ACK",null,message.getBytes(StandardCharsets.UTF_8));
    }
    long end = System.currentTimeMillis();
    System.out.println("异步确认消息发送耗时:"+(end-begin)+"ms");
}

四、总结

1. 优缺点

  • 单条同步发布确认:publishing messages individually, waiting for the confirmation synchronously: simple, but very limited throughput.
  • 批量同步发布确认:publishing messages in batch, waiting for the confirmation synchronously for a batch: simple, reasonable throughput, but hard to reason about when something goes wrong.
  • 异步发布确认:asynchronous handling: best performance and use of resources, good control in case of error, but can be involved to implement correctly.

2. 效率

测试结果可以看出异步确认效率是最高的,其次是批量确认,最后当然是一条一条的单条确认。

public static void main(String[] args) throws IOException, InterruptedException {
    //simpleConfirmMessage();//消息发送耗时:14492ms
    //batchConfirmMessage();//批量确认消息发送耗时:268ms
    //asynConfirmMessage();//异步确认消息发送耗时:36ms
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值