有关rabbitmq防止消息丢失的尝试和记录
rabbitmq版本:RabbitMQ 3.8.14
使用jar包版本: 2.4.3
场景一:测试rabbitmq自动提交和手动提交(手动使用ack)。代码如下:
yml配置:
spring:
rabbitmq:
addresses: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
#客户端接收消息配置
listener:
simple:
#最小并发
concurrency: 5
#最大并发
max-concurrency: 10
#接收消息方式 manual:手动 auto:自动 none: 不配置
acknowledge-mode: manual
#并发下欲取数据条数,1:每次取一条manual
prefetch: 1
#retry:
#enabled: true
#max-attempts: 5
#max-interval: 100000
#消息确认模式
publisher-confirm-type: simple
#可以确保消息在未被队列接收时返回,而不是丢弃
publisher-returns: false
connection-timeout: 5000
生产者:
/**
* @author: xiaobai
* @date: 2021/3/16 11:15
* @version:V1.0
* @description:消息生产者
*/
@Component
@Slf4j
public class SendOrder {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(Order order){
CorrelationData correlationData = new CorrelationData();
correlationData.setId(order.getMessageId());
rabbitTemplate.convertAndSend("order-exchange","order.1",order,correlationData);
log.info("消息发送成功:" +order.toString());
}
}
/**
* @author: xiaobai
* @date: 2021/3/16 14:10
* @version:V1.0
* @description:
*/
@Component
@Slf4j
public class OrderReceiver {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 笨方法
*/
public void consumer1(){
Object o = rabbitTemplate.receiveAndConvert("order-queue");
System.out.println("接收到的消息:" + o.toString());
}
/**
* RabbitListener 设置后可以自动创建exchange 和queue 并且创建绑定关系
* @param order
* @param headers
* @param channel
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "order-queue",durable = "true"),
exchange = @Exchange(value = "order-exchange",durable = "true",type = "topic"),
key = "order.#"
)
)
@RabbitHandler
public void consumer(@Payload Order order, @Headers Map<String,Object> headers, Channel channel) throws IOException {
log.info("消费者开始消费消息......" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
log.info("订单id:" + order.getId());
}
}
当属性值acknowledge-mode设置为manual时,即需要手动ack,才能通知生产者清除消息,上述代码执行后rabbitmq显示结果为:
上述结果证明了acknowledge-mode:manual 时,消息进入了Unacked(未确认消息)里面,此时需要手动ack,生产者才能删除此消息。
更改代码如下,加上最后两行,再次测试消息队列正常流转。
/**
* 由于设置了手动获取消息,必须要手动basicAck
* RabbitListener 设置后可以自动创建exchange 和queue 并且创建绑定关系
* @param order
* @param headers
* @param channel
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "order-queue",durable = "true"),
exchange = @Exchange(value = "order-exchange",durable = "true",type = "topic"),
key = "order.#"
)
)
@RabbitHandler
public void consumer(@Payload Order order, @Headers Map<String,Object> headers, Channel channel) throws IOException {
log.info("消费者开始消费消息......" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
log.info("订单id:" + order.getId());
//throw new RuntimeException();
Long delivery_tag = (Long)headers.get(AmqpHeaders.DELIVERY_TAG);
channel.basicAck(delivery_tag,false);
}