RocketMQ-消息重试

        任何MQ产品都可能存在各种异常,这些异常可能导致消息无法被发送到Broker,或者消息无法被消费者接收到,因此大部分MQ产品都会提供消息失败的重试机制。RocketMQ也不例外,在RocketMQ中消息重试分为生产者端重试和消费者端重试两种类型。

 

生产者端重试

        生产者端重试是指当生产者向Broker发送消息时,如果当前网络抖动等原因导致消息发送失败,此时可以通过手动设置发送失败重试次数的方式让消息重发一次。

@RunWith(SpringRunner.class)
@SpringBootTest
public class RockermqproducerApplicationTests {


    @Value("${apache.rocketmq.producer.producerGroup}")
    private String producerGroup;


    /**
     * NameServer 地址
     */
    @Value("${apache.rocketmq.namesrvAddr}")
    private String namesrvAddr;


    @Test
    public void contextLoads() {

        //生产者的组名
        DefaultMQProducer producer=new DefaultMQProducer(producerGroup);
        //指定NameServer地址,多个地址以 ; 隔开
        producer.setNamesrvAddr(namesrvAddr);
        //消息发送失败重试次数
        producer.setRetryTimesWhenSendFailed(3);
        //异步发送失败重试次数
        producer.setRetryTimesWhenSendAsyncFailed(3);
        //消息没有发送成功,是否发送到另外一个Broker中
        producer.setRetryAnotherBrokerWhenNotStoreOK(true);
        try {

            /**
             * Producer对象在使用之前必须要调用start初始化,初始化一次即可
             * 注意:切记不可以在每次发送消息时,都调用start方法
             */
            producer.start();
            for (int i=0;i<=10000;i++)
            {
                Message msg=new Message("topic_example_java","TagA",("Hello Java Demo RocketMQ:"+i).getBytes(Charset.defaultCharset()));
                SendResult result=producer.send(msg);
                System.out.println("消息发送结果:"+result);
            }

        }catch (Exception e)
        {
            e.printStackTrace();
        }finally {
            producer.shutdown();
        }
    }

}

        可以看到通过org.apache.rocketmq.client.producer.DefaultMQProducer类的setRetryTimesWhenSendFailed和setRetryTimesWhenSendAsyncFailed方法设置了重试次数。这里实现重试逻辑的代码主要在DefaultMQProducerImpl类的sendDefaultImpl方法中。

 

消费者端重试

        消费者端的失败一般分为两种情况,一种是由于网络等原因导致消息没法从Broker发送到消费者端,这时在RocketMQ内部会不断尝试发送这条消息,直到发送成功为止(比如向集群中的一个Broker实例发送失败,就尝试发往另一个Broker实例);二是消费者端已经正常接收到消息了,但是在执行后续消息处理逻辑时发生了异常,最终反馈给MQ消费者处理失败,例如所接收到的消息数据可能不符合本身的业务要求,如当前卡号未激活不能执行业务等,这时就需要通过业务代码返回消息消费的不同状态来控制。

        接下来以普通消费为例,看一下当消费者端出现业务消息消费异常之后时如何进行重试的。下面死在消费者端代码中注册消息监听器的consumeMessage方法最终返回的消息消费状态ConsumeConcurrentlyStatus的定义:

public enum ConsumeConcurrentlyStatus {
    CONSUME_SUCCESS,
    RECONSUME_LATER;

    private ConsumeConcurrentlyStatus() {
    }
}

        CONSUME_SUCCESS表示消费成功,这是正常业务代码中返回的状态。RECONSUME_LATER表示当前消费失败,需要稍后进行重试。在RocketMQ中只有业务消费者侧返了CONSUME_SUCCESS才会认为消息消费时成功的,如果返回RECONSUME_LATER,RocketMQ则会认为消费失败,需要重新投递。为了保证消息至少被成功消费一次,RocketMQ会把认为消费失败的消息发回Broker,在接下来的某个时间点(默认是10秒,可修改)再次投递给消费者。如果一直重复消息都失败的话,当失败累积到一定次数后(默认16次)将消息投递到死信队列(Dead Letter Queue)中,此时需要监控死信队列进行人工干预。

    @Bean("consumer1")
    public DefaultMQPushConsumer consumer1()
    {
        //创建一个消息消费者,并设置一个消息消费者组
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("niwei_consumer_group");
        //指定 NameServer 地址
        consumer.setNamesrvAddr("localhost:9876");
        consumer.setInstanceName("PushConsumer1");
        //设置 Consumer 第一次启动时从队列头部开始消费还是队列尾部开始消费
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        try {
            //订阅指定 Topic 下的所有消息
            consumer.subscribe("topic_example_java", "*");
            //注册消息监听器
            consumer.registerMessageListener(new MessageListenerConcurrently() {
                public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext context) {
                    //默认 list 里只有一条消息,可以通过设置参数来批量接收消息
                    if (list != null) {
                        for (MessageExt ext : list) {
                            String msgBody=new String(ext.getBody());
                            if (ext.getReconsumeTimes()==3)
                            {
                                saveReconsumeStillMessage(ext);
                                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                            }else
                            {
                                try {
                                    doBusiness(msgBody);
                                }catch (Exception e)
                                {
                                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                                }
                            }

                        }
                    }
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
            });

            // 消费者对象在使用之前必须要调用 start 初始化
            consumer.start();
            System.out.println("消息消费者已启动");
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return consumer;
    }

        示例中,判断当前消息是经过重试3次之后发出的,则不再继续执行业务代码,直接记录消息数据并返回消费成功状态。如果早业务的回调中没有处理好异常返回状态,而是在方法执行过程中抛出异常,那么RocketMQ认为消费也是失败的,会当作RECONSUME_LATER来处理。

       当使用顺序消费的回调(实现了MessageListenerOrderly接口)时,由于顺序消费是只有前一条消息消费成功了才能继续,所以在其消息状态定义(ConsumeOrderlyStatus)中并没有RECONSUME_LATER状态,而是用SUSPEND_CURRENT_QUEUE_A_MOMENT来暂停当前队列的消费动作,直到消息经过不断重试成功为止。

### 回答1: rocketmq-spring-boot-starter是一个基于Spring Boot框架的RocketMQ客户端启动器,可以方便地在Spring Boot应用中集成RocketMQ消息队列服务。它提供了一些自动配置和便捷的注解,使得开发者可以快速地使用RocketMQ进行消息的发送和消费。同时,它还支持RocketMQ的高可用、负载均衡、顺序消息等特性。 ### 回答2: RocketMQ是一个分布式的消息中间件系统,是由阿里巴巴公司开发和维护的。RocketMQ在分布式系统中能够提供高可用、高性能、可靠的消息服务。由于RocketMQ经历了多年的实践和迭代,因此它拥有了广泛的用户群体和丰富的功能特性。而RocketMQ-Spring-Boot-Starter就是为了更加方便RocketMQ在Spring Boot应用中的使用而开发的。下面就来介绍一下RocketMQ-Spring-Boot-Starter的使用和特点。 RocketMQ-Spring-Boot-Starter能够非常方便地集成RocketMQ消息系统到Spring Boot应用中。它提供了很多的配置选项,能够以最少的配置来完成RocketMQ的使用。在使用过程中,只需引入相应的依赖,然后在配置文件中添加配置即可。在消息生产者方面,只需要编写一个简单的类就可以实现发送消息的操作。在消息消费者方面,只需要编写一个监听器类就可以实现消息的接收和处理。而且RocketMQ-Spring-Boot-Starter提供了一些常用的RocketMQ操作,如日志记录、重试机制、事务消息等等,可以方便地进行日常开发和维护。 RocketMQ-Spring-Boot-Starter还有一些其他的特点。比如,它支持集成RocketMQ的多个版本,可以兼容不同版本的应用。同时,RocketMQ-Spring-Boot-Starter还支持多种序列化方式,如JSON、Protobuf等,可以满足不同的应用场景要求。而且,RocketMQ-Spring-Boot-Starter还提供了自定义的序列化插件和编码器,可以进一步满足自定义需求。 总之,RocketMQ-Spring-Boot-Starter是一个强大而实用的RocketMQ消息中间件集成框架。它可以有效地提高RocketMQ消息中间件的开发效率和应用性能,为开发人员提供更好的开发和维护体验。 ### 回答3: rocketmq-spring-boot-starter是一个开源项目,基于Spring Boot框架及Apache RocketMQ消息队列实现的一款快速构建分布式应用的工具,使得RocketMQ在Spring Boot框架下快速应用成为了一件简单的事情。该项目可以避免使用RocketMQ时需要手动编写大量重复的配置代码,还可以便捷地实现RocketMQ消息发送和消费。 在使用rocketmq-spring-boot-starter的时候,用户只需要简单配置相关配置项,就可以实现轻松的RocketMQ消息队列的使用。通过整合Spring Boot消息组件让开发者使用RocketMQ变得更加方便和容易。rocketmq-spring-boot-starter将RocketMQ客户端的配置和实例化放在自己的工程内,并将这些配置文件和实例自动注入到Spring Boot的应用环境中,从而让使用者可以直接使用aop来使用RocketMQ消息发送和消费功能。 此外,该项目还具有简单易用、高可靠、无侵入等特点,方便了开发者的代码管理和维护。用户可以少写一些繁琐重复的代码,只需在配置文件中配置相关项,就可以快速完成RocketMQ的使用,并利用Spring Boot的依赖注入,让代码结构更加简洁清晰,可维护性更高。 总之,rocketmq-spring-boot-starter的出现让使用RocketMQ消息队列的开发者可以更加轻松高效地进行消息处理,而且这个项目也在GitHub上得到了广泛的使用和支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值