2024年RocketMQ延迟消息的代码实战及原理分析,21条MySQL性能调优经验

Java面试核心知识点笔记

其中囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

Java中高级面试高频考点整理

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

最后分享Java进阶学习及面试必备的视频教学

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

// 设置NameServer的地址

consumer.setNamesrvAddr(“localhost:9876”);

// 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息

consumer.subscribe(“OneMoreTopic”, “*”);

// 注册回调实现类来处理从broker拉取回来的消息

consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {

System.out.printf(“%s %s Receive New Messages:%n”

, sdf.format(new Date())

, Thread.currentThread().getName());

for (MessageExt msg : msgs) {

System.out.printf(“\tMsg Id: %s%n”, msg.getMsgId());

System.out.printf(“\tBody: %s%n”, new String(msg.getBody()));

}

// 标记该消息已经被成功消费

return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;

});

// 启动消费者实例

consumer.start();

System.out.println(“Consumer Started.”);

}

}

再写一个延迟消息的生产者,用于发送延迟消息:

public class DelayProducer {

public static void main(String[] args) throws Exception {

SimpleDateFormat sdf = new SimpleDateFormat(“HH:mm:ss.SSS”);

// 实例化消息生产者Producer

DefaultMQProducer producer = new DefaultMQProducer(“OneMoreGroup”);

// 设置NameServer的地址

producer.setNamesrvAddr(“localhost:9876”);

// 启动Producer实例

producer.start();

Message msg = new Message(“OneMoreTopic”

, “DelayMessage”, “This is a delay message.”.getBytes());

//“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”

//设置消息延迟级别为3,也就是延迟10s。

msg.setDelayTimeLevel(3);

// 发送消息到一个Broker

SendResult sendResult = producer.send(msg);

// 通过sendResult返回消息是否成功送达

System.out.printf(“%s Send Status: %s, Msg Id: %s %n”

, sdf.format(new Date())

, sendResult.getSendStatus()

, sendResult.getMsgId());

// 如果不再发送消息,关闭Producer实例。

producer.shutdown();

}

}

运行生产者以后,就会发送一条延迟消息:

10:37:14.992 Send Status: SEND_OK, Msg Id: C0A8006D5AB018B4AAC216E0DB690000

10秒钟后,消费者收到的这条延迟消息:

10:37:25.026 ConsumeMessageThread_1 Receive New Messages:

Msg Id: C0A8006D5AB018B4AAC216E0DB690000

Body: This is a delay message.

延迟消息的原理分析

以下分析的RocketMQ源码的版本号是4.7.1,版本不同源码略有差别。

CommitLog

org.apache.rocketmq.store.CommitLog中,针对延迟消息做了一些处理:

// 延迟级别大于0,就是延时消息

if (msg.getDelayTimeLevel() > 0) {

// 判断当前延迟级别,如果大于最大延迟级别,

// 就设置当前延迟级别为最大延迟级别。

if (msg.getDelayTimeLevel() > this.defaultMessageStore

.getScheduleMessageService().getMaxDelayLevel()) {

msg.setDelayTimeLevel(this.defaultMessageStore

.getScheduleMessageService().getMaxDelayLevel());

}

// 获取延迟消息的主题,

// 其中RMQ_SYS_SCHEDULE_TOPIC的值为SCHEDULE_TOPIC_XXXX

topic = TopicValidator.RMQ_SYS_SCHEDULE_TOPIC;

// 根据延迟级别获取延迟消息的队列Id,

// 队列Id其实就是延迟级别减1

queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel());

// 备份真正的主题和队列Id

MessageAccessor.putProperty(msg

, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic());

MessageAccessor.putProperty(msg

, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId()));

msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));

// 设置延时消息的主题和队列Id

msg.setTopic(topic);

msg.setQueueId(queueId);

}

可以看到,每一个延迟消息的主题都被暂时更改为SCHEDULE_TOPIC_XXXX,并且根据延迟级别延迟消息变更了新的队列Id。接下来,处理延迟消息的就是org.apache.rocketmq.store.schedule.ScheduleMessageService

ScheduleMessageService

ScheduleMessageService是由org.apache.rocketmq.store.DefaultMessageStore进行初始化的,初始化包括构造对象和调用load方法。最后,再执行ScheduleMessageService的start方法:

public void start() {

// 使用AtomicBoolean确保start方法仅有效执行一次

if (started.compareAndSet(false, true)) {

this.timer = new Timer(“ScheduleMessageTimerThread”, true);

// 遍历所有延迟级别

for (Map.Entry<Integer, Long> entry : this.delayLevelTable.entrySet()) {

// key为延迟级别

Integer level = entry.getKey();

// value为延迟级别对应的毫秒数

Long timeDelay = entry.getValue();

// 根据延迟级别获得对应队列的偏移量

Long offset = this.offsetTable.get(level);

// 如果偏移量为null,则设置为0

if (null == offset) {

offset = 0L;

}

if (timeDelay != null) {

// 为每个延迟级别创建定时任务,

// 第一次启动任务延迟为FIRST_DELAY_TIME,也就是1秒

this.timer.schedule(

new DeliverDelayedMessageTimerTask(level, offset), FIRST_DELAY_TIME);

}

}

// 延迟10秒后每隔flushDelayOffsetInterval执行一次任务,

// 其中,flushDelayOffsetInterval默认配置也为10秒

this.timer.scheduleAtFixedRate(new TimerTask() {

@Override

public void run() {

try {

// 持久化每个队列消费的偏移量

if (started.get()) ScheduleMessageService.this.persist();

} catch (Throwable e) {

log.error(“scheduleAtFixedRate flush exception”, e);

}

}

}, 10000, this.defaultMessageStore

.getMessageStoreConfig().getFlushDelayOffsetInterval());

}

}

遍历所有延迟级别,根据延迟级别获得对应队列的偏移量,如果偏移量不存在,则设置为0。然后为每个延迟级别创建定时任务,第一次启动任务延迟为1秒,第二次及以后的启动任务延迟才是延迟级别相应的延迟时间。

然后,又创建了一个定时任务,用于持久化每个队列消费的偏移量。持久化的频率由flushDelayOffsetInterval属性进行配置,默认为10秒。

定时任务

最后

这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档

祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!

感谢大家的支持!!

image.png

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

定时任务

最后

这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档

祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!

感谢大家的支持!!

[外链图片转存中…(img-XfBegU6g-1715005582973)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 27
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL性能调优与架构设计》是一本介绍MySQL数据库性能优化和架构设计的指南。MySQL是一种常用的开源关系型数据库管理系统,广泛应用于互联网、企业和各种应用程序中。但是,在实际应用中,由于数据量的增加和访问负载的变化等原因,MySQL的性能会受到影响,为此需要进行相应的调优和架构设计。 该PDF文件主要介绍了如何通过调优和优化来提高MySQL的性能。首先,它详细介绍了MySQL的架构和基本原理,包括MySQL的体系结构、并发控制、索引优化等。然后,它介绍了如何通过优化查询、优化索引、优化表结构、对数据库进行分库分表等来提高MySQL的性能。此外,还介绍了如何选择合适的硬件和操作系统、配置参数等,以提高MySQL的性能。 此外,该PDF还介绍了MySQL的高可用性架构设计,包括主从复制、主从链式复制、多主复制等。这些架构设计可以提高MySQL的可用性和容错能力,确保数据的安全性和持久性。 总之,MySQL性能调优与架构设计是一个重要的课题,涉及到数据库的整体性能和稳定性。对于那些需要处理大量数据和高并发的应用程序来说,MySQL性能调优和架构设计是至关重要的,可以提高系统的响应速度和可靠性,保证系统的稳定运行。这本PDF文件详细介绍了MySQL性能调优和架构设计的方法和技巧,对开发人员和系统管理员都是很有参考价值的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值