用于可靠性的发布者确认
实现发布者确认,确保消息已被消息代理成功接收和处理。构建能够从网络或消息代理问题中恢复的可靠生产者。
用于可靠性的发布者确认 是 CoddyKit 上的免费 RabbitMQ Messaging & Async Systems 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 RabbitMQ Messaging & Async Systems 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 RabbitMQ Messaging & Async Systems 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Why Publisher Confirms?
When you send a message to RabbitMQ, how do you know if it actually arrived safely at the broker?
By default, producers send messages without waiting for any explicit confirmation from RabbitMQ. This is fast, but it means messages could be lost due to network issues or broker failures right after being sent.
Publisher Confirms are a mechanism that allows producers to receive acknowledgements (ACKs) from RabbitMQ when messages have been successfully received and processed by the broker.
The Unseen Gap in Delivery
Imagine sending an important order to a processing queue. Without publisher confirms, your application simply 'sends' the message and moves on.
- What if the network connection drops the message mid-flight?
- What if the RabbitMQ server crashes moments after receiving, but before persisting, your message?
Without a confirmation, your producer would assume success, potentially leading to data loss or inconsistent states in your system.
How Confirm Mode Works
To use publisher confirms, you enable 'confirm mode' on a channel. Once enabled, every message published on that channel is assigned a unique delivery tag.
- ACK (Acknowledgement): The broker sends an ACK back to the producer when a message has been successfully received, routed to its queues, and persisted (if durable).
- NACK (Negative Acknowledgement): The broker sends a NACK if it couldn't process the message (e.g., failed to route, internal error).
This feedback loop closes the 'delivery gap' between producer and broker.
Enabling Confirm Mode
Before publishing messages, you need to tell RabbitMQ that you want to use publisher confirms on your channel. This is a one-time setup for each channel.
Try running this example to see how to enable confirm mode:
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class ConfirmSetup {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost"); // Assumes RabbitMQ is running locally
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.confirmSelect(); // This line enables confirm mode
System.out.println("Channel is now in confirm mode.");
// Further publishing code would go here
}
}
}Synchronous Confirms: `waitForConfirms`
One way to use publisher confirms is synchronously. After publishing one or more messages, the producer can call channel.waitForConfirms() or channel.waitForConfirmsOrDie().
- This method blocks the producer until all messages published since the last call have been ACKed or NACKed.
- It's simple to implement but can significantly slow down throughput, as the producer waits for each batch of messages.
- Ideal for low-volume, critical messages where immediate confirmation is paramount.
Sync Confirm Code Example
This example shows a producer sending a single message and then waiting for its confirmation. If the message isn't confirmed within 5 seconds, it times out.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class SyncConfirmPublisher {
private static final String QUEUE_NAME = "sync_confirm_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.confirmSelect(); // Enable confirm mode
String message = "Hello, reliable world!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
// Wait for confirmation for up to 5 seconds
if (channel.waitForConfirms(5000)) {
System.out.println("Message confirmed by broker!");
} else {
System.out.println("Message not confirmed within timeout! It might be lost or delayed.");
}
}
}
}Asynchronous Confirms: Listeners
For higher throughput, you can use asynchronous publisher confirms. Instead of blocking, you register a ConfirmListener on the channel.
- The listener has two methods:
handleAck()for successful confirms andhandleNack()for negative confirms. - RabbitMQ delivers ACKs and NACKs to this listener, allowing your producer to continue publishing messages without waiting.
- This approach requires more complex logic to track unconfirmed messages, but offers superior performance for high-volume publishing.
Async Confirm Code Example
This example demonstrates an asynchronous publisher. It registers a listener to handle ACKs and NACKs without blocking the main thread.
Notice the Thread.sleep() to keep the program alive long enough to receive confirmations.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class AsyncConfirmPublisher {
private static final String QUEUE_NAME = "async_confirm_queue";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.confirmSelect(); // Enable confirm mode
// Store unconfirmed messages by their delivery tag
ConcurrentNavigableMap<Long, String> outstandingConfirms = new ConcurrentSkipListMap<>();
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
if (multiple) {
// Remove all messages up to this deliveryTag
outstandingConfirms.headMap(deliveryTag + 1).clear();
} else {
outstandingConfirms.remove(deliveryTag);
}
System.out.println(" [x] Message with deliveryTag " + deliveryTag + " ACKed! Remaining: " + outstandingConfirms.size());
}
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
String message = outstandingConfirms.get(deliveryTag);
System.out.println(" [!] Message '" + message + "' (deliveryTag " + deliveryTag + ") NACKed! Re-sending or logging error.");
// Handle NACK: re-publish, log, etc.
if (multiple) {
outstandingConfirms.headMap(deliveryTag + 1).clear();
} else {
outstandingConfirms.remove(deliveryTag);
}
}
});
String message = "Hello, async reliable world!";
long nextPublishSeqNo = channel.getNextPublishSeqNo();
outstandingConfirms.put(nextPublishSeqNo, message);
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "' (deliveryTag: " + nextPublishSeqNo + ")");
// Keep main thread alive for a moment to receive confirms
Thread.sleep(2000);
}
}
}Sync vs. Async: Choosing Wisely
The choice between synchronous and asynchronous confirms depends on your application's needs:
- Synchronous (
waitForConfirms):- Simpler to implement.
- Lower throughput, as it blocks.
- Good for low-volume, highly critical messages where immediate confirmation is essential.
- Asynchronous (
ConfirmListener):- More complex implementation (requires tracking unconfirmed messages).
- Higher throughput, as it doesn't block.
- Ideal for high-volume message publishing where performance is key.
Confirm Check
You've learned about publisher confirms. Let's see if you can answer this question.
Recap: Reliable Publishing
Congratulations! You've learned how to make your RabbitMQ producers truly reliable using publisher confirms.
- Publisher confirms ensure that messages sent by a producer are successfully received and processed by the RabbitMQ broker.
- You enable confirm mode on a channel using
channel.confirmSelect(). - Synchronous confirms (
waitForConfirms()) are simple but block, suitable for low volume. - Asynchronous confirms (
addConfirmListener()) provide higher throughput for high-volume scenarios, requiring more complex tracking of messages.
By implementing publisher confirms, you can build robust systems that minimize message loss and ensure critical data integrity.
常见问题解答
「用于可靠性的发布者确认」课时是免费的吗?
是的 — 「用于可靠性的发布者确认」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 RabbitMQ Messaging & Async Systems 课程的其余内容,请升级到 CoddyKit PRO。 RabbitMQ Messaging & Async Systems 课程共包含 4 节课。
「用于可靠性的发布者确认」这节课中我会学到什么?
实现发布者确认,确保消息已被消息代理成功接收和处理。构建能够从网络或消息代理问题中恢复的可靠生产者。 你通过在浏览器中直接运行的动手代码来练习 RabbitMQ Messaging & Async Systems,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 RabbitMQ Messaging & Async Systems 需要有经验吗?
无需任何先前经验。CoddyKit 上的 RabbitMQ Messaging & Async Systems 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「用于可靠性的发布者确认」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 RabbitMQ Messaging & Async Systems 课中编写并运行代码吗?
能。每节 RabbitMQ Messaging & Async Systems 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 持久化消息与队列
- 用于可靠性的发布者确认
- 消费者确认与重新入队
- 事务与发布者确认