RabbitMQ消息发布确任的三种方式

RabbitMQ消息发布确任的三种方式

单个确认

顾名思义就是消息生产方每发送一条消息,服务器都需要返回一条确认消息。

优点:每条消息都会进行确认,消息发送失败可以快速定位失败消息。

缺点:效率低

/**
     * 单个确认.
     *
     * @throws Exception Exception
     */
    public static void publishMessageIndividually() throws Exception {
        Channel channel = RabbitMqUtils.getChannel();

        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName, true, false, false, null);
        channel.confirmSelect();

        long begin = System.currentTimeMillis();
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = i + "Wk";
            channel.basicPublish("", queueName, null, message.getBytes(StandardCharsets.UTF_8));
            boolean flag = channel.waitForConfirms();
            if (flag) {
                System.out.println("消息发送成功");
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("发布1000个单独确认消息耗时:" + (end - begin));
    }
}

批量确认

可以设定生产方每发送n条消息,服务器返回一条确认信息。

优点:效率高

缺点:一旦出现消息发送失败,不容易确定是哪一条失败。

/**
 * 批量发布确认.
 *
 * @throws Exception Exception
 */
public static void publishMessageBatch() throws Exception {
    Channel channel = RabbitMqUtils.getChannel();

    String queueName = UUID.randomUUID().toString();
    channel.queueDeclare(queueName, true, false, false, null);
    channel.confirmSelect();
    long begin = System.currentTimeMillis();

    //批量确认消息的长度.

    int batchSize = 100;

    for (int i = 0; i < MESSAGE_COUNT; i++) {
        String message = i + "Wk";
        channel.basicPublish("", queueName, null, message.getBytes(StandardCharsets.UTF_8));
        if (i % batchSize == 0) {
            channel.waitForConfirms();
        }
    }

    long end = System.currentTimeMillis();
    System.out.println("发布1000个批量确认消息耗时:" + (end - begin));
}

异步批量确认

即发送方不必等待上一条确认消息返回才开始发送下一条,确认消息和发送消息是异步行为。也是每条消息都进行确认。

优点:可以达到最佳的性能和资源使用,在出现问题的情况下可以很好地控制。

缺点:实现稍微难一点。

/**
 * 异步确认.
 *
 * @throws Exception Exception
 */
public static void publishMessageAsync() throws Exception {
    Channel channel = RabbitMqUtils.getChannel();

    String queueName = UUID.randomUUID().toString();
    channel.queueDeclare(queueName, true, false, false, null);
    channel.confirmSelect();
    /**
     * 线程安全有序的一个map,适用于高并发的情况.
     */
    ConcurrentSkipListMap<Long, String> concurrentSkipListMap =
            new ConcurrentSkipListMap<>();
    //消息确认成功回调
    ConfirmCallback ackCallBack = (deliveryTag, multiple) -> {
        if (multiple) {
            ConcurrentSkipListMap<Long, String> confirmMap =
                    (ConcurrentSkipListMap<Long, String>) concurrentSkipListMap.headMap(deliveryTag);
            confirmMap.clear();
        }else {
            concurrentSkipListMap.remove(deliveryTag);
        }
        System.out.println("确认的消息:" + deliveryTag);
    };

    //消息确认失败回调
    ConfirmCallback nackCallBack = (deliveryTag, multiple) -> {
        String message = concurrentSkipListMap.get(deliveryTag);
        System.out.println("未确认的消息:" + deliveryTag);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    };
    //消息的监听器,监听异步回调的信息.
    channel.addConfirmListener(ackCallBack, nackCallBack);


    long begin = System.currentTimeMillis();
    //批量发消息.
    for (int i = 0; i < MESSAGE_COUNT; i++) {
        String message = i + "Wk";
        channel.basicPublish("", queueName, null, message.getBytes(StandardCharsets.UTF_8));
        System.out.println(i);
        concurrentSkipListMap.put(channel.getNextPublishSeqNo(), message);
    }

    long end = System.currentTimeMillis();
    System.out.println("发布1000个异步确认消息耗时:" + (end - begin));
}
posted @ 2022-08-07 22:16  昨夜风雨声  阅读(23)  评论(0编辑  收藏  举报  来源