• Rocketmq 重复消息,幂等


    一、为什么出现消息重复

    从 Product 看

    Rocketmq 提供三种发送消息模式

    同步发送:Producer 向 broker 发送消息,阻塞当前线程等待 broker 响应 发送结果。DefaultMQProducerImpl 中如果没有设置 超时、发送失败,就会重发。

    异步发送:先构建一个broker发送消息的任务,把任务提交给线程池,等执行完任务时,回调用户自定义的回调函数,执行处理结果。

    Oneway发送:只负责发送请求,不等待应答,

     

    注:同步发送、异步发送 如果发送成功,返回结果出现网络问题,会导致重新发送,多条重复消息。

    从 Consumer 看

    Broker 消息进度丢失,导致消息重复投递给 Consumer。

    Consumer 消费成功,但是因为网络问题,JVM 异常崩溃,导致rocketmq没收到 消费成功确认,会重复推送。

    注:从性能考虑,消费进度 用异步定时同步给 Broker。

     

     

     

    二、Rocketmq ack 机制保证消息消费成功。

    ACK

    发送者为保证消息肯定消费成功,需要使用方明确标识消费成功,rocketmq 才会认为消息消费成功。中途断电,抛出异常等都不会认为成功(会重新投递)。

    public enum Action {
        /**
         * 消费成功,继续消费下一条消息
         */
        CommitMessage,
        /**
         * 消费失败,告知服务器稍后再投递这条消息,继续消费其他消息
         */
        ReconsumeLater,
    }

    例:

    消费者回执

    
    
    import com.aliyun.openservices.ons.api.Action;
    import com.aliyun.openservices.ons.api.ConsumeContext;
    import com.aliyun.openservices.ons.api.Message;
    import com.aliyun.openservices.ons.api.MessageListener;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    public class RuleForwardListener implements MessageListener {
        private Logger log = LoggerFactory.getLogger(RuleForwardListener.class);
    
        @Override
        public Action consume(Message message, ConsumeContext context) {
            try {
                String msg = new String(message.getBody());
                log.info("rrpc response message:{}", msg);
                return Action.CommitMessage;  // 消费成功
            } catch (Throwable t) {
                log.error("rrpc-response error", t);
                return Action.ReconsumeLater;  // 消费失败
            }
        }
    }

    仅当回执函数返回 CommitMessage时,rocketmq 就会认为此消息消费成功。

    返回 ReconsumeLater ,rocketmq 认为消息消费失败。

     

    为保证消息肯定被至少消费成功一次,rocketmq 会把消息重发回 broker(topic不是原topic 而是消费组的 retry topic),在延迟的某个时间点(默认 10s, 可设置),再次投递到这个 ConsumerGroup。如果一直这样重复消费都失败,默认 16次,就会投递到 DLQ 死信队列。应用可以监控死信队列来做人工干预。

     

    修改重试时间

    broker 日志中发现默认重试时间:

    messageDelayLevel = 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

    可以在配置文件中设置:

    messageDelayLevel = 10s 1m 5m

    (或者在逻辑中,人工干预重复次数。达到次数后,返回 CommitMessage )

     

    三、解决重复消费 - 消费者实现 消费幂等。

    根据业务上 唯一 key 对消息做幂等处理。

    当出现消费者对某条消息重复消费的情况时,重复消费的结果与消费一次的结果相同,并且多次消费并未对业务系统产生任何负面影响,那么整个过程就可实现消息幂等

    Message 中的 key

    Message message = new Message(msgTopic, msgTag, "uuid", messageBody);
    SendResult sendResult = producer.send(message);

     

  • 相关阅读:
    Web前端之jQuery 的10大操作技巧
    Python开发者须知 —— Bottle框架常见的几个坑
    string、const char*、 char* 、char[]相互转换
    SLAM中的变换(旋转与位移)表示方法
    SLAM
    二叉搜索树(BST)
    Linux下OSG的编译和安装以及遇到的问题
    CMake--Set用法
    CMake--List用法
    php面向对象面试题
  • 原文地址:https://www.cnblogs.com/wgy1/p/14393736.html
Copyright © 2020-2023  润新知