RabbitMQ基本概念 http://t.csdn.cn/SYzGG
rabbitMQ使用方式 http://t.csdn.cn/tZV5K
-----------------------------------------------------------------------------------------------
消息持久化:当 RabbitMQ 服务停掉以后,消息生产者发送过来的消息不丢失
实现方式:队列持久化,消息持久化、发布确认(同时使用达到最优的消息持久化)
工具类:
public class RabbitMqUtils {
/**
* 获得获得信道channel
* @return
* @throws Exception
*/
public static Channel getChannel() throws Exception{
//创建一个连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.35.132");
factory.setUsername("itcast");
factory.setPassword("123321");
Connection connection = factory.newConnection();
return connection.createChannel();
}
}
public static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
// 声明队列
// 队列持久化设置(true 为持久化,false 为默认不持久化)
boolean durable = true;
channel.queueDeclare(QUEUE_NAME, durable,false,false,null);
// 发送消息
// MessageProperties.PERSISTENT_TEXT_PLAIN 用来设置 消息持久化
channel.basicPublish("",QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, "消息手动应答".getBytes(StandardCharsets.UTF_8));
System.out.println("消息发送成功");
}
public static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMqUtils.getChannel();
// 声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
// 发送消息
// MessageProperties.PERSISTENT_TEXT_PLAIN 用来设置 消息持久化
channel.basicPublish("",QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, "消息手动应答".getBytes(StandardCharsets.UTF_8));
System.out.println("消息发送成功");
}
将消息标记为持久化并不能完全保证不会丢失消息。尽管它告诉 RabbitMQ 将消息保存到磁盘,但是这里依然存在当消息刚准备存储在磁盘的时候 但是还没有存储完,消息还在缓存的一个间隔点。此时并没有真正写入磁盘。持久性保证并不强,进而需要引入发布确认
public class ConfirmMessage {
// 批量发消息的个数
public static final int MESSAGE_COUNT = 1000;
public static void main(String[] args) throws Exception {
// test1(); // 单个确认所有时间为:1364
// test2(); //批量确认所有时间为:105
test3(); // 异步批量确认所有时间为:74
}
public static void test1() throws Exception {
Channel channel = RabbitMqUtils.getChannel();
// 开启发布确认
channel.confirmSelect();
// 声明一个队列
channel.queueDeclare("singleConfirmQueue",true,false,false,null);
Long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
// 发送消息
channel.basicPublish("","singleConfirmQueue",null,"你好".getBytes());
// 单个发布确认
boolean b = channel.waitForConfirms();
if (b) {
System.out.println("消息发送成功");
}else{
System.out.println("消息发送失败");
}
}
Long end = System.currentTimeMillis();
System.out.println("单个确认所有时间为:"+(end-start));
}
public static void test2() throws Exception {
Channel channel = RabbitMqUtils.getChannel();
// 开启发布确认
channel.confirmSelect();
// 声明一个队列
channel.queueDeclare("singleConfirmQueue",true,false,false,null);
Long start = System.currentTimeMillis();
// 批量确认的长度
int batchSize = 100;
for (int i = 0; i < 1000; i++) {
// 发送消息
channel.basicPublish("","singleConfirmQueue",null,"你好".getBytes());
// 达到100条确认一次
if (i%batchSize == 0)
{
// 单个发布确认
boolean b = channel.waitForConfirms();
if (b) {
System.out.println("消息发送成功");
}
}
}
Long end = System.currentTimeMillis();
System.out.println("批量确认所有时间为:"+(end-start));
}
//异步批量确认
public static void test3() throws Exception{
Channel channel = RabbitMqUtils.getChannel();
// 开启发布确认
channel.confirmSelect();
// 声明一个队列
channel.queueDeclare("singleConfirmQueue",true,false,false,null);
/**
* 线程安全有序的一个哈希表,适用于高并发的情况
* 1.轻松的将序号与消息进行关联
* 2.轻松批量删除条目 只要给到序列号
* 3.支持并发访问
*/
ConcurrentSkipListMap outstandingConfirms = new ConcurrentSkipListMap<>();
System.out.println("------------------------------监听器-------------------------------------------------");
/**
* 准备消息监听器,监听哪些消息成功,哪些消息失败
*/
// 消息确认成功,回调函数
ConfirmCallback ackCallback =( deliveryTag, multiple)->{
// 判断是否是批量
if (multiple) {
// 2、删除掉已经确认的消息,剩下的都是未确认的消息
ConcurrentNavigableMap confirm = outstandingConfirms.headMap(deliveryTag);
confirm.clear();
}else {
outstandingConfirms.remove(deliveryTag);
}
System.out.println("确认的消息"+deliveryTag);
};
// 消息确认失败,回调函数
ConfirmCallback nackCallback = ( deliveryTag, multiple)->{
// 3、打印未确认的消息
String s = outstandingConfirms.get(deliveryTag);
System.out.println("未确认的消息的标记"+deliveryTag+"未确认的消息是:"+s);
};
// 监听是异步的
channel.addConfirmListener(ackCallback,nackCallback);
System.out.println("------------------------------监听器-------------------------------------------------");
Long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
String message = "message"+ i;
// 发送消息
channel.basicPublish("","singleConfirmQueue",null,message.getBytes());
// 1、记录所有要发送的消息
outstandingConfirms.put(channel.getNextPublishSeqNo(),message);
}
Long end = System.currentTimeMillis();
System.out.println("异步批量确认所有时间为:"+(end-start));
}
}