MQ常见问题解决思路
MQ消息丢失
1、Producer的消息丢失,即Producer发送了消息,但是MQ却未接收到消息:
@Component
@RequiredArgsConstructor
@Slf4j
public class MqProducer {
private final RabbitTemplate rabbitTemplate;
@PostConstruct
public void init() {
// Producer初始化为 confirm 模式,消息发送后会异步回调生产者,通过ack的布尔值判断消息是否正确被MQ接收
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
// 发送成功
log.info("----> Message sent successfully.");
} else {
// 发送失败
log.error("----> Failed to send message: " + cause);
}
});
}
public void sendMessage(String routingKey, Object message) {
rabbitTemplate.convertAndSend(MqConf.DIRECT_EXCHANGE, routingKey, JSON.toJSON(message));
log.info("----> Sent message: " + message);
}
}
spring:
rabbitmq:
host: xxxx
port: 5672
username: guest
password: guest
# confirm模式配置 !!!!
publisher-confirm-type: correlated
2、MQ内部的消息丢失:
消息持久化,当消息被成功消费时再删除。
设计分段式队列,避免消息在单一队列中堆积过多导致丢失。
利用死信队列,将未成功消费的消息再发一次MQ。
通过使用集群、复制和备份等技术手段,实现 MQ 的高可用和容灾能力,避免单点故障导致消息丢失。
3、Consumer的消息丢失
RabbitMQ默认为自动签收消息,因此Consumer在监听队列时,应开启手动签收模式@RabbitListener(queues = MqConf.HELLO_QUEUE, ackMode = "MANUAL")
MQ消息重复消费
给消息加上幂等性标识
,比如下单操作发消息给物流服务,即使message被重复消费,查询数据库已存在对应的物流ID,则不执行对应的业务操作。
MQ保证分布式事务
1、Producer保证message成功发送(不丢失,不重复)
2、Consumer保证message成功消费(不丢失,不重复)
死信队列
死信队列,即一个消息配置了普通交换机+普通队列,还配置了死信交换机+死信队列。因此这个message存在两个消费者,当消息出于以下3中情况之一时:
1. message被消费者拒绝签收,使用
channel.basicNack()
或channel.basicReject()
拒绝签收
并且此时第二个属性被设置为false。
2. message在队列的存活时间超过设置的TTL时间。
3. 消息队列的message数量已经达到最大队列长度。
该message将会被丢进死信队列中,由死信消费者消费。反之则由普通消费者消费。
延时队列
延时队列即特殊的死信队列,即不配备普通消费者,那么一直不被消费的message在MQ中肯定会超过设置的TTL时间,就必然会被死信消费者消费。即达到了延迟一段时间执行业务行为
的效果。