一)演示消息丢失现象
服务消费端
@Component
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "${spring.rabbitmq.queue.error.name}", autoDelete = "true"),
exchange = @Exchange(value = "${spring.rabbitmq.exchange.name}", type = ExchangeTypes.DIRECT),
key = "${spring.rabbitmq.queue.error.key}"
)
)
public class ErrorQueue {
@RabbitHandler
public void info(String msg) {
System.out.println("error......" + msg);
}
}
服务提供端
@Component
public class Send {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 设置交换器的名称
*/
@Value(value = "${spring.rabbitmq.exchange.name}")
private String exchange;
/**
* 设置发送的key
*/
@Value(value = "${spring.rabbitmq.queue.error.key}")
private String key;
public void send(String msg){
this.rabbitTemplate.convertAndSend(exchange,key,msg);
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTests
{
@Autowired
private Send send;
@Test
public void contextLoads() throws InterruptedException
{
int flag = 0;//标记
while (true)
{
flag++;
Thread.sleep(2000);
this.send.send("info"+flag);
}
}
}
演示消息丢失
1.消息正常发送
服务正在被消费
此时我们停止服务消费端让,服务生产端继续运行
消息的消费从62开始了,中间的产生的消息不见了,这就是消息丢失,
autoDelete 属性
解决出现的消息的问题
@Queue: 当所有消费客户端连接断开后,是否自动删除 队列 true:删除 false:不删除
@Exchange:当所有绑定队列都不在使用时,是否自动 删除交换器 true:删除 false:不删除
意思就是通过autoDelete属性保持队列的状态,就算出服务消费端宕机的情况,让队列依然存在,只是的有对应的服务进行消费而已,RabbitMQ会将没有消费的请求保存在对类中,一旦服务重启服务将继续消费
测试
通过管理界面已经有队在运行了
在服务消费到26的时候停掉服务消费端
在看管理界面,队列并没有消失,而且没有被处理的消息缓存在队列中
从新开启消费服务,接着停止的位置继续消费
以上就是RabbitMQ的消息持久化操作和相关的设置
二)RabbitMQ - ACK
演示ACK反馈的问题
借助上面的项目进行演示
1.在服务消费方添加一个的异常的抛出,让服务消费方无法正常的进行服务的消费
@Component
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "${spring.rabbitmq.queue.error.name}", autoDelete = "false"),
exchange = @Exchange(value = "${spring.rabbitmq.exchange.name}", type = ExchangeTypes.DIRECT),
key = "${spring.rabbitmq.queue.error.key}"
)
)
public class ErrorQueue {
@RabbitHandler
public void info(String msg) {
System.out.println("error......" + msg);
throw new RuntimeException();//抛出一个的异常
}
}
2.测试代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTests
{
@Autowired
private Send send;
@Test
public void contextLoads() throws InterruptedException
{
Thread.sleep(2000);
this.send.send("info");
}
}
3.结果
我们发现服务端在一直对请求进行处理,这就是因为ACK返回的原因,如果请求被处理完毕消费端会反馈给的RabbtiMQ,告诉它这个消息已经被消费过了,而此时在方法执行中出现异常,此时的消息并没有反馈,导致的RabbitMQ不知道此消息是否完成了消费,会在此将此消息放入队列交给消费端进行消费,如此反复进如了死循环。
解决办法一:
加上try-catch语句块
try
{
System.out.println("error......" + msg);
throw new RuntimeException();
}catch (Exception e){
}
解决办法二:
在全局配置文件内配置重复请求的次数
#开启重试
spring.rabbitmq.listener.simple.retry.enabled=true
#设置重复次数 默认是3次
spring.rabbitmq.listener.simple.retry.max-attempts=5