RabbitMQ的Producer发送消息保证消息不丢失方案
在rabbitTemplate异步确认的基础上
1 ,为当前message生成一个唯一的id,并在本地缓存已发送的message
2, 通过confirmCallback监听被确认的ack【虽然没有message本身,但是confirmCallback()方法有个correlationData参数,可以通过此参数将msgId返回回来】,将被确认的message从本地删除
3, 定时扫描本地的message,如果大于一定时间未被确认,则重发
当然了,这种解决方式也有一定的问题: 想象这种场景,rabbitmq接收到了消息,在发送ack确认时,网络断了,造成客户端没有收到ack,重发消息。(相比于丢失消息,重发消息要好解决的多,需要在consumer端做到幂等)。
@Override
public DetailRes send(Object message) {
try {
//生成一个唯一的msgId
String id = retryCache.generateId();
//缓存发送的message
retryCache.add(id, message);
//CorrelationData可为当前消息附带上id信息,在调用callback()方法时可以取到该值
//(因为callback时没有message信息的)
rabbitTemplate.correlationConvertAndSend(message, new CorrelationData(id));
} catch (Exception e) {
return new DetailRes(false, "");
}
return new DetailRes(true, "");
}
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (!ack) {
log.info("send message failed: " + cause + correlationData.toString());
} else {
//取出发送消息时在correlationData中附带的msgId
retryCache.del(correlationData.getId());
}
});