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));
}