深入浅出RocketMQ(五):延时消费源码分析:用户下单锁库存与超时释放

RocketMQ-延时消息Demo及实现原理分析 文章目录延时消息Producer Demo源码分析延时消息持久化内部变量含义初始化load方法start方法延时消息调度总结 假设有这么一个需求,用户下单后如果30分钟未支付,则该订单需要被关闭。你会怎么做? 最简单的做法,可以服务端启动个定时器,隔个几秒扫描数据库中待支付的订单,如果(当前时间-订单创建时间)>30分钟,则关闭订单。 这种方案优点是实现简单,缺点呢? 定时扫描意味着隔个几... 阅读详情

前言

    今天我们来聊聊RocketMQ中的延时消费,主要在于了解RocketMQ是怎么帮我们实现延时消费以及模拟业务场景下如何使用延时消费实现功能。

1、业务场景

    先从一个简单的业务场景入手,假如你在做电商模块的秒杀系统,不考虑风险控制数据统计这些逻辑,那么最简单的流程应该是

        1. 锁定库存
        2. 创建订单
        3. 返回结果
        4. 支付完成
        5. 更新数据

    当用户请求进来时我们去查询一次商品库存是否满足需求,如果OK就修改当前商品库存随后创建好订单然后告知用户结果。

    至于高并发情况下如何保证商品库存更新这一操作的安全性,我们可以采用乐观锁的形式去修改库存结果,对于失败的情况只要直接告知用户秒杀失败即可,这并不是我们这章需要讨论的。

    看起来这个逻辑似乎没有问题,但是我们要考虑一些极端的情况

    就比如:A用户下单之后迟迟没有付款,那只要A用户不付款,这个库存就一直属于该用户

    这个逻辑很明显是有问题的,而现实生活中也不会出现这种情况,在电商系统中,经常会有一个超时自动释放库存的逻辑。

2、解决方案

    12306相信大家都用过,当我们选好票之后会自动跳转到支付页面,并要求我们需要30分钟内完成支付,否则该订单自动取消。

    这个逻辑就是我们刚才说的超时自动释放库存(或者是自动取消订单),通过rocketMQ提供的延时消费功能,我们可以很无脑的实现这个逻辑。

    为什么说是无脑呢?因为在API使用层面来说实在是太简单了,我们只需要在创建Message之后设置延迟级别,然后就完事了……

message.setDelayTimeLevel(9);

    当然,这也是因为RocketMQ只需要保证这个消息的发送能按用户设置的延时级别准时投递给消费者就行了,至于释放库存这一逻辑,那是你业务上的事情。

    所以我们要做的事情就是,在消费到延时消息后,检查订单状态是否已经完成,如果用户没有支付的话则将订单设置为超时,然后将库存还回去。

3、实现原理

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

 // 延迟级别
 // 当前支持的延迟时间
 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
 //  分别对应级别
 1 2 3....................

    当然,我们更关注的是,RocketMQ是怎么实现延时消费的。在RocketMQ GitHub官方文档上面给的解释是这样的:

在这里插入图片描述
    官方文档的解释其实已经很清晰了,消费者消费消息是根据其订阅的Topic中有没有消息来决定的,而RocketMQ就是把你需要延时消费的消息暂存在另一个队列,直到时间到了再投递给你想要的Topic去消费。

4、源码分析

    光靠我这样说大家可能印象不够深刻,接下来我将通过对RocketMQ4.5.1的源码进行简单解析,让大家对broker是如何处理延时消息有个更加全面的了解。

    (插一嘴,因为RocketMQ基于maven,因此构建源码环境很简单,上github clone下来等maven自动构建完就好了,Spring5的源码环境构建实在是让我心累……)

4.1 源码构建

https://github.com/apache/rocketmq/tree/release-4.5.1

    通过该链接clone下来之后,直接用IDEA打开,静静等待它自动帮你构建好环境就好了。

    有了4.5.1的源码之后,大家看着源码可能会不知所措,这么多的东西该从哪里看起呢?有些初学者阅读源码的方式就是:找到启动类,一行一行阅读下去。

    实际上这样是很傻的,不仅效率不高,而且很容易迷失在代码发散的各个分支功能中。真正阅读源码的好习惯是:带着问题去找答案。

4.2 源码分析

    就比如我们现在,我们想要知道broker是怎么帮我们解决延时消费问题的,那么我们就直接根据关键字查找即可:


在这里插入图片描述
    点进来我们可以看到,这个类是一个内部类,而且还是继承于TimeTask,那么很自然的一个直觉就是,一定有其它地方把它作为一个定时任务来启动。在什么地方启动呢我们待会再看。

    先观察一下这个内部类的成员变量和构造器,其实不用我说你们都懂,delayLevel是延时级别,offset是消费偏移量,构造器则是为这两个成员变量设置值。

    run方法做的事情我们就不看了,猜测它应该就是根据当前延时级别去把延时队列里的数据投递到对应的Topic里。



在这里插入图片描述
    接下来我们看一下这个内部类在哪个地方使用到了,通过查找功能我们很快就能定位到ScheduleMessageService的start()方法里:

public void start() {
        if (started.compareAndSet(false, true)) {
            this.timer = new Timer("ScheduleMessageTimerThread", true);
            for (Map.Entry<Integer, Long> entry : this.delayLevelTable.entrySet()) {
                Integer level = entry.getKey();
                Long timeDelay = entry.getValue();
                Long offset = this.offsetTable.get(level);
                if (null == offset) {
                    offset = 0L;
                }

                if (timeDelay != null) {
                    this.timer.schedule(new DeliverDelayedMessageTimerTask(level, offset), FIRST_DELAY_TIME);
                }
            }
            ...省略其他逻辑
    }

    其他逻辑我们统统忽略,最重要的显然是这个for循环:通过遍历delayLevelTable这个Map得到每个消费级别对应的时延以及消费偏移量,然后每个级别启动一个1秒执行一次的定时任务。

结尾

    通过查看源码我们可以发现,在BrokerServer上,会有专门的TimeTask去把到达延迟消费时间后的消息投递到对应的Topic上。但是这样其实可能存在一个问题,假如当前延迟时间队列中的内容数量十分多,就有可能会出现投递不及时的情况。因此对于定时调度这一功能实现,使用专门的定时调度中间件或许会更好一点。

源码分析RocketMQ顺序消息消费实现原理 切莫死记硬背,小心面试官直接让你出门右拐1000道互联网Java面试题: 阅读详情

相关推荐

RocketMQ请求超时的排查处理过程

从日志分析、源码分析、抓包处理、报文分析、堆栈分析等角度分享一次RocketMQ请求响应慢的排查处理过程。

林风自在 4820

SpringCloud技术栈微服务架构天猫商城企业级开发实战(附源码)

天猫商城是一个基于SSM框架的综合性B2C电商平台,需求设计主要参考天猫商城的购物流程:用户从注册开始,到完成登录,浏览商品,加入购物车,进行下单,确认收货,评价等一系列操作。 作为模拟天猫商城系统的核心组成部分之一,采用SSM框架的天猫数据管理后台包含商品管理,订单管理,类别管理,用户管理和交易额统计等模块,实现了对整个商城的一站式管理和维护。本课程是一门专业的Java微服架构开发实战课程,主要讲解了当下流行的SpringBoot框架、SpringCloud架构以及与第三方技术整合开发实战内容。通过本课程的学习,能够理解并掌握SpringBoot的基础知识,同时能够掌握SpringBoot与常用的第三方技术整合实现实际开发中的业务需求,包括实现Web开发、数据访问、缓存管理、安全管理、消息服务、任务管理等;了解并掌握SpringCloud微服务架构的基础知识及相关组件的应用,掌握微服务架构在企业级开发的实践,建立起微服架构思想。项目技术栈:采用SpringBoot简化商城系统的初始搭建以及开发过程采用SpringMVC+Spring+IBatis完成项目的整合采用Mysql作为数据库存储,Druid配置数据库连接池采用SpringCloud+Netflix 微服务技术栈的实战开发使用Redis完成缓存的数据存储,搭建Redis搭建主从、哨兵、集群应用,保证Redis的高可用使用ElasticSearch全文检索系统进行商品数据搜索,使用ElasticSearch搭建搜索服务的高可用使用Ngnix实现页面动静分离与负载均衡的配置采用FastDFS文件储存系统文件存储,完成广告图片、商品图片的上传和存储系统使用采用CAS+shiro单点登录系统实现用户认证使用ECharts根据后台查询数据生成图表使用POI实现了商城盈利状况的Excel表格导出。商品的详情页使用Thymeleaf完成页面静态化,减少页面数据展示延迟项目中使用SpringBoot下的Aop + 自定义注解完成用户行为记录,日志采集后台管理系统使用Shiro实现登录验证和权限管理(超级管理员、管理员、产品编辑员)项目整合微信完成订单的支付使用Redission完成分布式锁,生成订单的编号使用SpringCloud Alibaba Seat完成下订单模块的分布式事务(新增订单表,库存减少,库存超卖设计)使用RabbitMQ 做消息队列,完成订单未支付自动取消和模块直接的解耦合使用Quartz任务调度,完成缓存的定时刷新,保证缓存的一致性使用本地消息表机制完成消息然队列RabbitMQ消息可靠性传输订单支付模块使用微信扫码支付,并设置订单超时自动取消通过Jquery实现前端校验,通过基于Hibernate的Valida注解实现后端的校验功能使用Base64编码对Json数据传输进行编码和解码项目使用RESTful设计风格实现资源的访问,实现前后端分离项目使用聚合数据第三方短信平台完成用户的登陆功能项目使用SpringBoot整合JavaMail完成邮件的发送项目使用SpringBoot整合Swagger2生成接口文档使用PostMan完成接口的测试项目的测试:SpringTest、dbunit、EasyMock使用Docker 进行应用的自动化打包和发布、自动化测试和持续集成、部署和调整其他应用使用 PowerDesigner,完成数据库的建模项目使用禅道进行BUG管理环境采用Maven实施多模块项目构建,采用Git进行项目版本管理 架构解读:  项目部分截图:              讲义部分截图:          

为什么开源的RocketMQ没有支持任意精度的延时消息

写在前面 在我们日常的开发中,经常会遇到这样"在一段时间之后,触发某一个事件"的业务场景。如: 电商平台下单后30分钟不支付订单自动取消 红包24小时不领取自动退还 常见的解决方案 1.定时扫描 事先记录事件的触发时间点,定时任务不停查数据库对比触发时间。 这种方式不实时,随着定时任务的执行频率变高,触发实时性会有所提升,但是频繁地扫描增加了数据库的压力,也是最简单的做法。 2.jdk的...

weixin_41229818的博客 1296

高性能`锁库存`/`释放库存`重构实战

记录一次高性能锁库存/释放库存重构实战 编写本文的主要目的有两个,一是输出文档方便回顾,二是从网上很难找到高性能锁库存实战,本文可供大家参考。 本次重构有几大难点: 1、随着业务发展存在诸多历史遗留问题,技术债积重难返 2、重新组建重构团队,人永远是最重要的 3、团队在业务和系统实现细节方面存在诸多盲点 4、跨团队协作问题,言外之意人才是最大的不可控因素 重构之路举步维艰艰,所以一定要保持良好的心态,去积极应对各种各样的问题和难题。尤其涉及到跨团队协作时一定要慎重,何时该妥协,何时该硬刚,一切以重构上线为目

白云 3429

Spring Boot集成RocketMQ实现普通、延时、事务消息发送接收、PULL消费模式及开启ACL | Spring Cloud 30

现在开始我们正式学习`Spring Boot`中集成`RocketMQ`使用,,在本章节主要进行对以下部分讲解说明: - 普通消息的发送接收 - 延时消息的发送接收 - 事务消息的发送接收 - 发送端和接收端开启`ACL` - `PULL`模式消费及`@ExtRocketMQConsumerConfiguration`使用

gmHappy 1万+

RocketMQ Push消息给消费者 解析——图解、源码级解析

文章目录概述Push消息消费流程开启消息消费接收消息 概述 RocketMQ中消费者有两种方式获得消息来消费:Push模式和Pull模式 Push模式:服务端将消息推送到客户端 Pull模式:客户端不断请求服务端,或许消息 实际上这两种模式的底层实现都是采用的Consumer主动拉取消息的方式 在Push方式里,把Consumer轮询过程封装起来了,并注册了MessageListener监听器,当拉取到消息后唤醒监听器来消费,所以感觉消息就像是被服务端推过来的一样 在Pull模式中,Consumer

如切如磋,如琢如磨 2329

高并发引起的库存超发解决方案

库存设计:设置锁定库存和总库存,当用户下单未支付时锁定库存,支付成功时释放锁定库存并扣减总库存,当30分钟用户还未支付,此时释放锁定库存不扣减总库存。 一、库存超发原因: 下单流程: 当库存为1时,两个用户同时下单,查询库存时都有库存,都通过了库存数量校验,下单成功库存为-1。 二、解决方案: (1)悲观锁 实现方式:查询时添加更新锁。 实现原理:使当前线程持有数据库记录行更新...

qq_41354978的博客 4942

Rocketmq源码分析之消息消费(五)

以上是RocketMQ消息消费的源码分析,总体流程为消费者订阅消息、从消息队列拉取消息、将消息处理器封装成ConsumeConcurrentlyService对象,并加入ConsumeMessageService对象维护的ConcurrentMap中,然后对多个消息进行循环处理,调用消息处理器的consumeMessage()方法进行消息消费,最后进行消费进度的提交。当消息队列中有消息需要被消费时,会触发Consumer对象的消息处理器进行消息消费。本文以推模式为例进行源码分析。

程序员Linc 649

Redis高并发分布式锁实战(Setnx、Redisson及底层源码、RedLock):库存扣减中理解分布式锁的含义【收获满满】

一、分布式锁场景 1、互联网秒杀 2、抢优惠券 3、接口幂等性校验 二、扣减库存实战 1、不加锁版本 依赖: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.0.RELEASE</version&

沮丧的南瓜 3134

STM32新手必看:AHT20温湿度传感器实战指南(附完整I2C代码)

本文详细介绍了如何使用STM32驱动AHT20温湿度传感器,包括硬件连接、I2C通信协议解析、驱动代码优化及实战调试技巧。通过对比AHT20与DHT11、SHT30等传感器的性能,突出AHT20的高性价比优势,并提供完整的I2C代码示例,帮助新手快速上手嵌入式传感器开发。

weixin_29163857的博客 293

HI3516CV610海思SOC:超高清智慧视觉开发全攻略

本文全面解析海思HI3516CV610 SOC在超高清智慧视觉开发中的应用。该芯片集成双核A7处理器、1Tops NPU、AI ISP及4K视频编码器,专为智能摄像头设计。文章详细介绍了开发环境搭建、核心硬件架构、媒体处理平台(MPP)实战、AI算法集成与系统调优等全流程攻略,帮助开发者高效构建稳定可靠的视觉AI产品。

weixin_29269441的博客 1254

基于消息队列实现分布式锁

这种基于Redisson的方式能够简化分布式锁的实现,同时也提供了更多的功能和配置选项。当然,在实际应用中,仍然需要考虑连接池、异常处理等问题。基于消息队列实现分布式锁可以借助于消息队列的排他消费者特性来实现。下面是一个基于Redis作为消息队列的分布式锁示例,使用。如果获取成功,则执行相应的操作,并在完成后使用。在这个示例中,我们使用了Redisson库来获取分布式锁,通过。首先,确保你的Java项目中引入了Redisson客户端库。

kankan_s的专栏 1171

嵌入式八股文-ARM

嵌入式八股文总结(ARM篇)-优快云博客现象:I2C死锁就是时钟线SCL一直处于高电平,数据线SDA一直处于低电平。从机拉低数据线SDA时(发送应答信号给主机时或发送数据0时)主机意外复位,主机复位后时钟线SCL就为高电平了,此时,SCL为高电平而SDA为低电平,主机就以为有其他设备占有了总线,而SCL为高电平时 数据位SDA不允许有变化,意思是:主机就一直等待时钟线SDA拉高,而从机就一直等待时钟线SCL拉高 就造成了死锁的现象。解决方法:1.选择带有复位功能的从设备,复位后SDA被拉高。

m0_63127436的博客 1259

这些年遇到的RocketMQ消息消费超时/消费异常重试机制导致的重复消费问题(并发消费和顺序消费)源码分析

图文详述并发消费模式和顺序消费下RocketMQ消息消费超时、消息消费出现异常时的重试机制原理、源码

健身变秃,coding变强 1万+

生物信息学工具链搭建:用conda一键搞定MCScanX所有依赖(Ubuntu20.04实测)

本文详细介绍了在Ubuntu20.04系统上使用conda一键部署MCScanX及其所有依赖的高效方法,解决了传统源码编译安装中的依赖冲突问题。通过conda环境管理工具,研究者可以快速搭建生物信息学工具链,实现基因组共线性分析的高效运行,显著提升研究效率。

backprop5master的博客 247

Ubuntu升级遇到grub-efi-amd64-signed报错?3步搞定这个烦人的EFI目录问题

本文详细解析了Ubuntu系统升级时遇到的“grub-efi-amd64-signed”报错及“cannot find EFI directory”问题。通过剖析UEFI启动机制与EFI系统分区原理,提供了从诊断到修复的三步解决方案,帮助用户快速解决因EFI目录未挂载导致的升级中断,确保系统引导正常。

assembly8low的博客 585

RocketMQ源码分析(三) 消费者

rocketmq 推模式消费者/拉模式消费者

caicongyang 1566

ParaView: GUI 轴网格

ParaView: GUI 轴网格

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1923

惊呆:RocketMQ顺序消息,是“4把锁”实现的(顺序消费)

一条订单产生的三条消息:订单创建、订单付款、订单完成。上面三消息是有序的,消费时要按照这个顺序依次消费才有意义,但是不同的订单之间这些消息是可以并行消费的。什么是顺序消息?顺序消息是指对于一个指定的 Topic ,消息严格按照先进先出(FIFO)的原则进行消息发布和消费,即先发布的消息先消费,后发布的消息后消费。分区有序消息全局有序消息我们做一个关于顺序消费的总结:通过4把锁的机制,消息队列 messageQueue 的数据都会被消费者实例单线程的执行消费;

架构师尼恩 2325

RuyiDify如何创建知识库API密钥:让程序安全访问知识库

知识库 API Key 是程序访问知识库的钥匙。创建它很简单,但真正重要的是知道它能做什么、应该放在哪里、不能暴露给谁。RuyiDify 讲这一步,不是为了让大家多记一个按钮,而是为了把知识库从“人工上传资料”推进到“程序化维护资料”。

未来已来,AI时代,学AI编程,做AI量化,就来大鹏AI教育。 136

国科大学习资料--遥感原理集图像处理(尤红建)--2019年期末考试

国科大学习资料–遥感原理集图像处理(尤红建)–2019年期末考试 国科大学习资料–遥感原理集图像处理(尤红建)–2019年期末考试 国科大学习资料–遥感原理集图像处理(尤红建)–2019年期末考试 ================================================================== ================================================================== ==============

无名何许人的博客 1469

RocketMQ源码分析 consumer消费,并发、顺序、延时、事务消息总结

1.消费客户端启动流程 先贴下consume client启动的流程图 消费端启动和producer启动很类似,可以和producer启动进行对比。 不同之处是消费端的PullMessageService、RebalanceService才有真正作用,而producer该两个服务线程是无用的,这两个服务线程也是消费端的核心。 2.消费队列负载均衡RebalanceService 先...

https://www.cnblogs.com/zhangyjblogs/ 1093

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

RocketMQ学习(五)——RocketMQ消费之pull和push

MQ中Pull和Push的两种消费方式 对于任何一款消息中间件而言,消费者客户端一般有两种方式从消息中间件获取消息并消费。严格意义上来讲,RocketMQ并没有实现PUSH模式,而是对拉模式进行一层包装,名字虽然是 Push 开头,实际在实现时,使用 Pull 方式实现。通过 Pull 不断不断不断轮询 Broker 获取消息。当不存在新消息时,Broker 会挂起请求,直到有新消息产生,取消挂起...

hxyascx的博客 8783

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

RocketMQ一个新的消费组初次启动时从何处开始消费呢?

本文详细介绍一个新的消费组在启动时从何处开始消费,并信息介绍了CONSUME_FROM_MAX_OFFSET、CONSUME_FROM_FIRST_OFFSET、CONSUME_FROM_TIMESTAMP其计算逻辑,解答CONSUME_FROM_MAX_OFFSET在什么情况下不生效并如何解决。

中间件兴趣圈 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

RocketMQ 源码分析 —— Message 顺序发送与消费

本文详细介绍了RocketMQ顺序消息的实现机制。顺序消息要求消费顺序与生产顺序一致,适用于订单处理、数据同步等场景。RocketMQ通过"局部顺序"设计实现全局扩展性:发送端使用MessageQueueSelector确保同一业务ID消息进入同一队列;Broker端通过CommitLog和ConsumeQueue保证存储顺序;消费端采用队列锁和顺序消费服务确保顺序处理。系统还包含完善的异常处理、重试机制和性能优化方案,如队列数量调优、批处理设置等,在保证顺序性的同时兼顾系统性能。典型问

油墨香^-^的博客 945

RocketMQ源码分析:Consumer消费偏移量

我们先看一幅图消费偏移量offset就是记录消费者的消费进度的。也是rocketmq保证消息不会重复消费的核心(当然,极端情况下还是可能会导致重复消费)。consumequeue中一个消息的索引单元就是一个offset值。在分析rocketmq的消费者是如何利用这个offset完成消息消费的之前,我们先看下broker端是如何管理这些offset值的。消费者客户端本地维护一个offset表,消费者消费完成后先更新到本地offset表中。...

老男孩的架构路 2821
上一篇: 深入浅出RocketMQ(四):广播、集群、拉取、推送、顺序消费
下一篇: java集成ldap验证用户名和密码
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值