RocketMQ入门-RocketMQ延时消息

RocketMQ延时消息

本篇基于RocketMQ集群开发,如需了解集群的搭建,可参考文章RocketMQ集群安装

Producer

public class SchedulerMessageProducer {

    public static void main(String[] args) throws Exception {
        // 1.指定生产者组
        DefaultMQProducer defaultMQProducer = new DefaultMQProducer(MyRocketMqConstant.SchedulerLearn.SCHEDULER_LEARN_PRODUCER_GROUP);
        // 2.关联注册中心
        defaultMQProducer.setNamesrvAddr(MyRocketMqConstant.NAME_SRV);
        // 3.启动生产者
        defaultMQProducer.start();
        int totalMessageToSend = 10;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        for (int i = 0; i < totalMessageToSend; i++) {
            String str = "This is a scheduler message";
            Message message = new Message(MyRocketMqConstant.SchedulerLearn.SCHEDULER_LEARN_TOPIC
                    , MyRocketMqConstant.SchedulerLearn.SCHEDULER_LEARN_TAG_A
                    , "KEY" + i, str.getBytes(StandardCharsets.UTF_8));
            // 4.设置延时等级3,这个消息将在10s后发送(现在只支持固定的几个时间,详见delayTimeLevel)
            // 生产者主线程直接遍历跑完,消息的延迟应该是broker根据message的DELAY属性来判断是否延迟存储消息的
            message.setDelayTimeLevel(3);
            SendResult sendResult = defaultMQProducer.send(message);
            System.out.println(String.format("SendResult status:%s,queueId:%d,body:%s",
                    sendResult.getSendStatus(),
                    sendResult.getMessageQueue().getQueueId(),
                    str+",msgSendBrokerTime "+sdf.format(new Date())));
        }

        // 关闭生产者
        defaultMQProducer.shutdown();
    }
}

Consumer

public class SchedulerMessageConsumer {
    public static void main(String[] args) throws Exception {
        // 1.消费者关联消费者组
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(MyRocketMqConstant.SchedulerLearn.SCHEDULER_LEARN_CONSUMER_GROUP);
        // 2.关联注册中心
        consumer.setNamesrvAddr(MyRocketMqConstant.NAME_SRV);
        // 3.订阅消息
        consumer.subscribe(MyRocketMqConstant.SchedulerLearn.SCHEDULER_LEARN_TOPIC
                ,MyRocketMqConstant.SchedulerLearn.SCHEDULER_LEARN_TAG_A);
        // 4.注册监听器
        consumer.registerMessageListener(new MessageListenerOrderly() {

            Random random = new Random();

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                for (MessageExt msg : msgs) {
                    Date msgDate = new Date(msg.getStoreTimestamp());
                    Date now = new Date();
                    System.out.println("[consumerThread=" + Thread.currentThread().getName()
                            + "] [broker=" + msg.getBrokerName() + msg.getStoreHost()
                            + "] [queueId=" + msg.getQueueId()
                            + "] [now"+ sdf.format(now) +" storeDate"+sdf.format(msgDate)
                            + "] [content=" + new String(msg.getBody()) +"]");
                }


                try {
                    // 模拟业务处理
                    TimeUnit.SECONDS.sleep(random.nextInt(10));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return ConsumeOrderlyStatus.SUCCESS;
            }
        });

        System.out.println("消费者启动");
        consumer.start();
    }
}

测试结果

message.setDelayTimeLevel(3);设置出的消息延时为10s,生产者控制台输出的msgSendBrokerTime和消费者接收到消息的storeTimestamp如果差距跟10s过大时,需要重置服务器的时间,设置服务器时间,可参考下面的***设置服务器时间跟随网络时间***。

观察输出消息,能够发现消息发送时间msgSendBrokerTime和消息存储时间storeDate相差的时间为10s,这是符合我们生产者发送消息设置的延时等级的。

tips:RocketMQ源码示例中说:*您将会看到消息的消费比存储时间晚10秒。*实践证明这个说法不正确,应该是:消息的存储时间比发送消息时间晚10s。

生产者

SendResult status:SEND_OK,queueId:1,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:2,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:3,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:0,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:1,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:2,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:3,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:0,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:1,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07
SendResult status:SEND_OK,queueId:2,body:This is a scheduler message,msgSendBrokerTime 2021-04-18 18:11:07

消费者

[consumerThread=ConsumeMessageThread_11] [broker=broker-b/192.168.15.16:10911] [queueId=1] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_14] [broker=broker-b/192.168.15.16:10911] [queueId=2] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_13] [broker=broker-b/192.168.15.16:10911] [queueId=3] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_5] [broker=broker-a/192.168.15.15:10911] [queueId=0] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_4] [broker=broker-a/192.168.15.15:10911] [queueId=1] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_8] [broker=broker-a/192.168.15.15:10911] [queueId=2] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_3] [broker=broker-a/192.168.15.15:10911] [queueId=3] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_10] [broker=broker-b/192.168.15.16:10911] [queueId=0] [now2021-04-18 18:11:17 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_14] [broker=broker-b/192.168.15.16:10911] [queueId=2] [now2021-04-18 18:11:24 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]
[consumerThread=ConsumeMessageThread_11] [broker=broker-b/192.168.15.16:10911] [queueId=1] [now2021-04-18 18:11:26 storeDate2021-04-18 18:11:17] [content=This is a scheduler message]

设置服务器时间跟随网络时间

登录服务器,检查当前的时间是否与网络时间一致。不一致需要重新校验,校验步骤如下,其中ntpdate 0.asia.pool.ntp.org可以多执行一次,避免校验不准确

[root@rocketmq-slave02 rocketmq-all-4.8.0-bin-release]# yum -y install ntp ntpdate
#<============time.nist.gov、time.nuri.net、0.asia.pool.ntp.org、1.asia.pool.ntp.org、2.asia.pool.ntp.org、3.asia.pool.ntp.org中任意一个,只要保证可用就OK。
[root@rocketmq-slave02 rocketmq-all-4.8.0-bin-release]# ntpdate 0.asia.pool.ntp.org
18 Apr 17:36:00 ntpdate[5269]: step time server 80.241.0.72 offset 51.385016 sec
[root@rocketmq-master01 rocketmq-all-4.8.0-bin-release]# ntpdate 0.asia.pool.ntp.org
18 Apr 18:09:14 ntpdate[42050]: step time server 211.233.84.186 offset 3.543249 sec
#<============写入硬件时间
[root@rocketmq-slave02 rocketmq-all-4.8.0-bin-release]# hwclock --systohc
[root@rocketmq-slave02 rocketmq-all-4.8.0-bin-release]# timedatectl
      Local time: 日 2021-04-18 17:36:18 CST
  Universal time: 日 2021-04-18 09:36:18 UTC
        RTC time: 日 2021-04-18 09:36:19
       Time zone: Asia/Shanghai (CST, +0800)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a
[root@rocketmq-slave02 rocketmq-all-4.8.0-bin-release]# 

总结

延时消息的使用场景

比如电商里,提交了一个订单就可以发送一个延时消息,1h后去检查这个订单的状态,如果还是未付款就取消订单释放库存。

延时消息的使用限制

// org/apache/rocketmq/store/config/MessageStoreConfig.java

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

现在RocketMq并不支持任意时间的延时,需要设置几个固定的延时等级,从1s到2h分别对应着等级1到18; 消息消费失败会进入延时消息队列,消息发送时间与设置的延时等级和重试次数有关,详见代码SendMessageProcessor.java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值