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参数,表示到这个序号之前所有的消息都得到了处理。所有的消息只会被Ack或Nack一次,不会出现既被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());
}
}
来源:oschina
链接:https://my.oschina.net/xiaominmin/blog/4493352