一、提出问题
生产者将消息发送出去后,消息是否到达RabbitMq服务器呢?默认的情况下,是不知道的
二、引入消息确认机制
两种方式:
1.AMQP实现事务机制
2.confirm模式
三、AMQP实现事务机制
3.1 简单示例
txSelect():用户将当前channel设置成transaction
txCommit():提交事务
txRollback():回滚事务
package com.wj.transation.config;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @创建人 wj
* @创建时间 2018/11/2
* @描述
*/
public class MqConfig {
public static Connection getConnection() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection= factory.newConnection();
return connection;
}
}
生产者:
package com.wj.transation;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.wj.transation.config.MqConfig;
/**
* @创建人 wj
* @创建时间 2018/11/5
* @描述 用事务模式,进行消息确认机制
*/
public class TxSend {
private static final String QUEUE_NAME = "test_queue_tx";
public static void send() throws Exception {
Connection connection = MqConfig.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String msg = "hello tx!";
try {
// 用户将当前channel设置成transaction
channel.txSelect();
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
// 异常,使回滚
int x=1/0;
System.out.println("【发送端】消息:"+msg);
//提交事务
channel.txCommit();
} catch (Exception e) {
channel.txRollback();
System.out.println("发生异常,回滚");
}
channel.close();
connection.close();
}
}
消费者
package com.wj.transation;
import com.rabbitmq.client.*;
import com.wj.transation.config.MqConfig;
import java.io.IOException;
/**
* @创建人 wj
* @创建时间 2018/11/5
* @描述
*/
public class TxRecv {
private static final String QUEUE_NAME = "test_queue_tx";
public static void recv() throws Exception {
Connection connection = MqConfig.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicConsume(QUEUE_NAME, true, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[接收端]消息:" + new String(body, "utf-8"));
}
});
}
}
运行结果:
注释异常,运行结果:
3.2 缺点
使用事务机制的话会降低RabbitMQ的性能,降低了吞吐量,增加了channel的请求数,耗时
四、Confirm模式
confirm模式分为三种:(差异在于生产者,前面二者串行)
普通模式(一个)
批处理 (多个)
异步confirm模式
4.1普通模式
package com.wj.confirm.general;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.wj.confirm.util.ConnectionUtil;
/**
* @创建人 wj
* @创建时间 2018/11/5
* @描述 普通模式
*/
public class Send {
private static final String QUEUE_NAME="general_queue";
public static void send() throws Exception {
Connection connection=ConnectionUtil.getConnection();
Channel channel=connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产者调用confirmSelect 将channel设置为confirm模式
channel.confirmSelect();
String msg="hello confirm!";
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
if (!channel.waitForConfirms()){
System.out.println("消息发送失败!");
}else {
System.out.println("消息发送成功!");
}
}
}
4.2批量模式
package com.wj.confirm.batch;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.wj.confirm.util.ConnectionUtil;
/**
* @创建人 wj
* @创建时间 2018/11/5
* @描述 批量模式
*/
public class Send {
private static final String QUEUE_NAME = "batch_queue";
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//生产者调用confirmSelect 将channel设置为confirm模式
channel.confirmSelect();
// 批量
for (int i = 0; i < 10; i++) {
String msg = "hello confirm! [" + i + "]";
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
}
//确认
if (!channel.waitForConfirms()) {
System.out.println("消息发送失败!");
} else {
System.out.println("消息发送成功!");
}
}
}
4.3异步confirm模式
package com.wj.confirm.asynchronization;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.wj.confirm.util.ConnectionUtil;
import java.io.IOException;
import java.util.*;
/**
* @创建人 wj
* @创建时间 2018/11/5
* @描述 批量模式
*/
public class Send {
private static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws Exception{
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//生产者调用confirmSelect 将channel设置为confirm模式
channel.confirmSelect();
// 未确认的消息标识
final SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>());
// 通道添加监听
channel.addConfirmListener(new ConfirmListener() {
// 没有问题的handleAck
@Override
public void handleAck(long deliverTag, boolean multiple) throws IOException {
if (multiple) {
System.out.println("---handleNack----multiple");
confirmSet.headSet(deliverTag + 1).clear();
} else {
System.out.println("false");
confirmSet.remove(deliverTag);
}
}
@Override
public void handleNack(long deliverTag, boolean multiple) throws IOException {
if (multiple) {
System.out.println("---handleNack----multiple");
confirmSet.headSet(deliverTag + 1).clear();
} else {
System.out.println("false");
confirmSet.remove(deliverTag);
}
}
});
String msg = "hello confirm——ack! ";
while (true) {
long seqNo = channel.getNextPublishSeqNo();
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
confirmSet.add(seqNo);
}
}
}
1,2的顺序,2,1也可以,推荐是2,1
消费者:
package com.wj.confirm.asynchronization;
import com.rabbitmq.client.*;
import com.wj.confirm.util.ConnectionUtil;
import java.io.IOException;
/**
* @创建人 wj
* @创建时间 2018/11/5
* @描述
*/
public class Recv {
private static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws Exception{
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicConsume(QUEUE_NAME,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[接收端]消息:"+new String(body,"utf-8"));
}
});
}
}
gitHub: