何为可靠性
当mq异步发送一条信息,但是mq处理消息时发生错误,无法达到预期处理结果。
比如当我们购买一件商品时,完成了支付动作,这个时候将修改订单状态交给mq处理,但是mq发生了错误,导致支付状态与订单状态不一致。
解决办法
1.生产者可靠性
1.1 retry重试机制
在yml文件中添加如下信息
connection-timeout: 1s #连接超时时间
publisher-returns: true #开启publish-return功能
# 这里支持两种类型:simple:同步等待confirm结果,直到超时;
# correlated:异步回调,定义ConfirmCallback,MQ返回结果时会回调这个ConfirmCallback
publisher-confirm-type: correlated
template:
retry:
enabled: true #开启重试机制
initial-interval: 1000ms #初始失败等待时长
multiplier: 1 #失败时长等待时长倍数 下次等待时长 = multiplier * initial-interval
max-attempts: 3 #最大重试次数
1.2 生产者确认机制.
Publisher Confirm
编写配置类
public class MqConfirmConfig implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
log.debug("收到消息的return callback,exchange:{},key:{},text:{},code:{},msg:{}",
returnedMessage.getExchange(),returnedMessage.getRoutingKey(),
returnedMessage.getReplyText(),returnedMessage.getReplyCode(),
returnedMessage.getMessage());
}
});
}
}
Publisher Return
在发送消息时编写代码,在失败结果中处理
void testRerun() throws InterruptedException {
CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
@Override
public void onFailure(Throwable ex) {
log.error("消息回调失败:",ex);
}
@Override
public void onSuccess(CorrelationData.Confirm result) {
log.debug("收到confirm callback回调");
if(result.isAck()){
log.debug("消息发送成功,收到ack");
}else{
log.debug("消息发送失败,收到nack,原因:{}",result.getReason());
}
}
});
rabbitTemplate.convertAndSend("hmall.direct","red","hellp",cd);
Thread.sleep(2000);
}
2.MQ的可靠性
在默认情况下,RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟。这样会导致两个问题:
- 一旦MQ宕机,内存中的消息会丢失
- 内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞
2.1交换机可靠性
消费者确认机制
为了确认消费者是否成功处理消息,RabbitMQ提供了消费者确认机制,(Consumer Acknowledgement)。当消费者处理消息结束后,应该向RabbitMQ发送一个回执,告知RabbitMQ自己消息处理状。回执有三种可选值:
- ack:成功处理消息,RabbitMQ从队列中删除该消息。
- nack:消息处理失败,RabbitMQ需要再次投递消息。
- reject:消息处理失败并拒绝该消息,RabbitMQ从队列中删除该消息。
spring:
rabbitmq:
listener:
simple:
acknowledge-mode: auto
在acknowledge-mode中配置,有三种方式:
- none:不处理。即消息投递给消费者后立刻ack,消息会立即从MQ删除,非常不安全,不建议使用。
- manual:手动模式。需要自己在业务代码中调用api,发送ack或reject,存在业务入侵,但更灵活。
- auto:自动模式。SpringAMQP利用AOP对我们的消息处理逻辑做了环绕增强,当业务正常执行时则自动返回ack。
- 如果是业务异常,会自动返回nack。
- 如果是消息处理或校验异常,自动返回reject。
消费者重试机制,设置MessageRecoverer