• RabbitMQ消息的重复消费问题


    消息重复消费是分布式消息传递系统常见的一个问题。在RabbitMQ中,可以通过以下几种策略解决或者缓解消息重复消费的问题:

    1. 确保消息处理的幂等性:设计消费者的消息处理逻辑,确保即使消息被多次消费也不会对系统造成不良影响。

    2. 消息去重策略:在消息或处理逻辑中使用唯一标识符,并在消费者中实现去重检查。

    3. 手动确认与重试机制:通过手动确认(acknowledgment)消息,可以控制消费者何时确认消息,如果处理失败可以选择重新入队或者丢弃。

    4. 使用RabbitMQ的消息属性RabbitMQ的消息属性messageId或者correlationId可以作为消息的唯一标识符。

    5. 事务或者发布确认:使用RabbitMQ的事务功能或者发布确认保证消息被成功发送。

    代码演示

    以下是一个Java代码示例,其中消费者实现了手动确认和幂等性处理:

    import com.rabbitmq.client.*;
    
    import java.io.IOException;
    import java.util.HashSet;
    import java.util.Set;
    
    public class IdempotentConsumer {
    
        private final static String QUEUE_NAME = "idempotent_queue";
        private static final Set<String> processedMessageIds = new HashSet<>();
    
        public static void main(String[] argv) throws Exception {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            final Channel channel = connection.createChannel();
    
            boolean durable = true;
            channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
    
            System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
    
            channel.basicQos(1); // fair dispatch
    
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                AMQP.BasicProperties props = delivery.getProperties();
                String messageId = props.getMessageId(); // 假设每条消息都有唯一的messageId
    
                try {
                    if (processedMessageIds.contains(messageId)) {
                        System.out.println("Duplicate message detected: " + messageId);
                        channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                        return;
                    }
    
                    String message = new String(delivery.getBody(), "UTF-8");
                    System.out.println(" [x] Received '" + message + "'");
    
                    // 模拟业务逻辑处理
                    doWork(message);
    
                    // 标记消息为已处理
                    processedMessageIds.add(messageId);
    
                    // 手动确认消息
                    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                } catch (Exception e) {
                    // 处理异常情况,可以选择重新入队
                    channel.basicNack(delivery.getEnvelope().getDeliveryTag(), false, true);
                }
            };
    
            boolean autoAck = false; // 关闭自动确认
            channel.basicConsume(QUEUE_NAME, autoAck, deliverCallback, consumerTag -> {});
        }
    
        private static void doWork(String task) {
            // 模拟工作
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    在这个示例中,我们创建了一个processedMessageIds集合,用于追踪已经处理过的消息ID,确保我们不会重复处理相同的消息。在实际应用中,这个集合可能需要持久化或者分布式存储,以便跨多个消费者实例共享状态。

    解决重复消费问题的关键点:

    1. 消息唯一标识:使用messageId或者correlationId等属性,确保每个消息都有唯一的标识符。

    2. 手动ACK:通过手动发送ack或nack来控制消息的确认状态。

    3. 幂等性操作:确保消费者处理消息的操作是幂等的。

    4. 持久化状态记录:将已处理消息的标识符状态持久化存储,以便在消费者重启后仍然能够识别哪些消息已处理。

    5. 错误处理:恰当处理消费者中的异常,以及决定是丢弃消息还是重试。

    6. 事务性消息处理:在必要的情况下结合数据库事务等,保证消息的处理与业务逻辑的执行具有原子性。

    结合源码

    在深入源码层面,可以查看RabbitMQ Java客户端库中与消息确认相关的接口和类实现,比如Channel接口的basicAckbasicNackbasicReject方法,了解其内部工作原理。

    为了更好地控制消息确认和重试逻辑,可能需要结合业务逻辑和消息中间件的高级特性,例如死信队列(DLX)和延迟队列等。这些特性能够帮助更好地管理无法处理的消息,以及实现复杂的消费逻辑。

  • 相关阅读:
    odoo15 crm 客户资料导出按钮的实现
    Python手写贝叶斯网络
    Docker中部署elasticsearch
    Windowsold文件夹作用以及删除方法
    python关键字
    PyTorch 从tensor.grad 看 backward(权重参数) 和 gradient accumulated
    实用调试技巧,debug
    基于若依ruoyi-nbcio支持flowable流程角色,同时修改流转用户为username,流程启动做大调整(二)
    直播倒计时,PyTorch Conference 2022 今晚开启
    【数据结构】链表
  • 原文地址:https://blog.csdn.net/qq_43012298/article/details/135881613