java rocketMQ实现

组成:

nameServer 提供注册中心的服务,负责broker的管理,以及topic路由信息的管理。
brokerServer 则主要负责消息的存储、投递和查询及高可用。
Producer 连接nameServer获取到broker信息后,发送信息到对应的broker。
Consumer 同样先连接 nameServer,查询topic路由信息,然后连接broker消费消息。

延迟消息:

定时是设定未来具体时间要干某事,延时则是推迟多久干某事

使用场景:

典型场景一:分布式定时任务(延迟发送邮件)
典型场景二:超时处理(订单超时未支付的场景)
典型场景三:限时优惠活动(商品促销,活动开始,发送一个两小时后触发的定时消息,活动结束时恢复原价。)
典型场景四:工作流程控制(某个步骤完成,下个步骤自动完成)

RocketMQ 中,一共内置了 18 个等级的延时时间,也就是 Producer 无法随便选择延时时间,而是只能在这 18 个时间里面选择。发送延时消息只需要 setDelayTimeLevel 就可以。

原理:

1、Producer 发送延时消息后,会立马给到 Broker

2、Broker 将会将该消息发送到一个新的专门存放延时消息的 Topic,这个 Topic 的名字就叫 SCHEDULE_TOPIC_XXXX 。这个 Topic 中一共有 18 个队列用来对应 18 个等级的延时 level。按照消息延时 level (从预设的 18 个里面选)进入到不同的队列中。

3、这个和原先那套存储类似,Broker 会将消息存储到 commitlog 下,也会保存一份数据到 consumerQueue(这里有些懵的可以看之前的存储篇)。

4、在 Broker 内部有核心线程池,里面有 18 个关于延时消息的线程,专门用来监察有没得延时消息。每个线程消费对应队列的消息,每 100 ms 消费一次,不断循环,消费逻辑就是得到队列中的 consumerQueue 和 offset,就可以获得延时消息,拿到延时消息的延迟时间和当前时间对比,判断是否到期,如果到期,则会将消息丢回原 Topic 和队列。

5、你也可以理解是 RocketMQ 的一种消息过滤,在消息过滤篇也提过一嘴,但内部实现原理就是基于 Broker 内部线程池定时调度消费延时队列中消息。

所以回到上面的问题,为什么要不允许用户自定义延时时间呢?原因还是 RocketMQ 内置了不同 level 队列对应的线程,这样能减少时间轮的复杂度,避免系统滥用,减少了动态计算和管理不同延时时间的复杂性,性能方面也得到了极致的优化。

实战:

1、创建生产者

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;

public class DelayMessageProducer {
    public static void main(String[] args) throws Exception {
        // 创建一个生产者,并指定生产者组名
        DefaultMQProducer producer = new DefaultMQProducer("delay_producer_group");

        // 指定NameServer地址
        producer.setNamesrvAddr("localhost:9876");

        // 启动生产者
        producer.start();

        for (int i = 0; i < 10; i++) {
            // 创建消息实例,指定主题、标签和消息体
            Message msg = new Message("DelayTopic", "DelayTag", 
                ("Hello RocketMQ " + i).getBytes());

            // 设置延时等级3,对应10s
            msg.setDelayTimeLevel(3);

            // 发送消息
            SendResult sendResult = producer.send(msg);
            System.out.printf("发送结果:%s%n", sendResult);
        }

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

2、创建消费者

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.List;

public class DelayMessageConsumer {
    public static void main(String[] args) throws Exception {
        // 创建一个消费者,并指定消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("delay_consumer_group");

        // 指定NameServer地址
        consumer.setNamesrvAddr("localhost:9876");

        // 订阅主题和标签
        consumer.subscribe("DelayTopic", "*");

        // 注册回调接口来处理从broker拉取的消息
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, 
                                                            ConsumeConcurrentlyContext context) {
                for (MessageExt msg : msgs) {
                    System.out.printf("接收到消息:%s %n", new String(msg.getBody()));
                }
                // 标记该消息已经被成功消费
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        // 启动消费者
        consumer.start();

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值