MQ常见问题解决思路

发布时间 2023-09-26 01:15:34作者: ashet

MQ避免消息丢失

1、Producer的消息丢失,即Producer发送了消息,但是MQ却未接收到消息:

Producer初始化为 confirm 模式,消息发送后会异步回调生产者,生产者即可知道消息是否发送成功
@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);
            }
        });
        rabbitTemplate.setMandatory(true);
    }


    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时间,就必然会被死信消费者消费。即达到了延迟一段时间执行业务行为的效果。