延时实现

简介: 本节介绍了多种关闭过期订单的实现方案,包括定时任务、JDK延迟队列、Redis过期监听、Redisson延迟队列、RocketMQ延迟消息及RabbitMQ死信队列。各自优缺点明显,适用于不同业务场景,如定时任务适合小数据量,RocketMQ适合高并发解耦场景,而Redisson则使用简单且高效。选择时需综合考虑系统复杂度、数据量及可靠性要求。

2.1 定时任务

通过定时任务关闭订单,是一种成本很低,实现也很容易的方案。通过简单的几行代码,写一个定时任务,定期扫描数据库中的订单,如果时间过期,就将其状态更新为关闭即可。

优点:实现容易,成本低,基本不依赖其他组件。

缺点:

时间可能不够精确。由于定时任务扫描的间隔是固定的,所以可能造成一些订单已经过期了一段时间才被扫描到,订单关闭的时间比正常时间晚一些。

增加了数据库的压力。随着订单的数量越来越多,扫描的成本也会越来越大,执行时间也会被拉长,可能导致某些应该被关闭的订单迟迟没有被关闭。

总结:采用定时任务的方案比较适合对时间要求不是很敏感,并且数据量不太多的业务场景。

2.2 JDK 延迟队列 DelayQueue

DelayQueue 是 JDK 提供的一个无界队列,我们可以看到,DelayQueue 队列中的元素需要实现 Delayed,它只提供了一个方法,就是获取过期时间。

用户的订单生成以后,设置过期时间比如 30 分钟,放入定义好的 DelayQueue,然后创建一个线程,在线程中通过 while(true)不断的从 DelayQueue 中获取过期的数据。

优点:不依赖任何第三方组件,连数据库也不需要了,实现起来也方便。缺点:

因为 DelayQueue 是一个无界队列,如果放入的订单过多,会造成 JVM OOM。DelayQueue 基于 JVM 内存,如果 JVM 重启了,那所有数据就丢失了。

总结:DelayQueue 适用于数据量较小,且丢失也不影响主业务的场景,比如内部系统的一些非重要通知,就算丢失,也不会有太大影响。

2.3 redis 过期监听

redis 是一个高性能的 KV 数据库,除了用作缓存以外,其实还提供了过期监听的功能。在 redis.conf 中,配置 notify-keyspace-events Ex 即可开启此功能。

然后在代码中继承 KeyspaceEventMessageListener,实现 onMessage 就可以监听过期的数据量。

我们可以发现,其本质也是注册一个 listener,利用 redis 的发布订阅,当 key 过期时,发布过期消息(key)到 Channel :keyevent@*:expired 中。

在实际的业务中,我们可以将订单的过期时间设置比如 30 分钟,然后放入到 redis。30 分钟之后,就可以消费这个 key,然后做一些业务上的后置动作,比如检查用户是否支付。

优点: 由于 redis 的高性能,所以我们在设置 key,或者消费 key 时,速度上是可以保证的。

缺点:由于 redis 的 key 过期策略原因,当一个 key 过期时,redis 无法保证立刻将其删除,自然我们的监听事件也无法第一时间消费到这个 key,所以会存在一定的延迟。另外,在 redis5.0 之前,订阅发布中的消息并没有被持久化,自然也没有所谓的确认机制。所以一旦消费消息的过程中我们的客户端发生了宕机,这条消息就彻底丢失了。

总结:redis 的过期订阅相比于其他方案没有太大的优势,在实际生产环境中,用得相对较少。

2.4 Redisson 分布式延迟队列

Redisson 是一个基于 redis 实现的 Java 驻内存数据网格,它不仅提供了一系列的分布式的 Java 常用对象,还提供了许多分布式服务。

Redisson 除了提供我们常用的分布式锁外,还提供了一个分布式延迟队列RDelayedQueue,他是一种基于 zset 结构实现的延迟队列,其实现类是RedissonDelayedQueue。

优点:使用简单,并且其实现类中大量使用 lua 脚本保证其原子性,不会有并发重复问题。

缺点:需要依赖 redis(如果这算一种缺点的话)。

总结:Redisson 是 redis 官方推荐的 JAVA 客户端,提供了很多常用的功能,使用简单、高效,推荐大家尝试使用。

2.5 RocketMQ 延迟消息

延迟消息,当消息写入到 Broker 后,不会立刻被消费者消费,需要等待指定的时长后才可被消费处理的消息,称为延时消息。

在订单创建之后,我们就可以把订单作为一条消息投递到 rocketmq,并将延迟时间设置为 30 分钟,这样,30 分钟后我们定义的 consumer 就可以消费到这条消息,然后检查用户是否支付了这个订单。

通过延迟消息,我们就可以将业务解耦,极大地简化我们的代码逻辑。

优点:可以使代码逻辑清晰,系统之间完全解耦,只需关注生产及消费消息即可。另外其吞吐量极高,最多可以支撑万亿级的数据量。

缺点:相对来说 mq 是重量级的组件,引入 mq 之后,随之而来的消息丢失、幂等性问题等都加深了系统的复杂度。

总结:通过 mq 进行系统业务解耦,以及对系统性能削峰填谷已经是当前高性能系统的标配。

2.6 RabbitMQ 死信队列

除了 RocketMQ 的延迟队列,RabbitMQ 的死信队列也可以实现消息延迟功能。

当 RabbitMQ 中的一条正常消息,因为过了存活时间(TTL 过期)、队列长度超限、被消费者拒绝等原因无法被消费时,就会被当成一条死信消息,投递到死信队列。

基于这样的机制,我们可以给消息设置一个 ttl,然后故意不消费消息,等消息过期就会进入死信队列,我们再消费死信队列即可。

通过这样的方式,就可以达到同 RocketMQ 延迟消息一样的效果。

优点:同 RocketMQ 一样,RabbitMQ 同样可以使业务解耦,基于其集群的扩展性,也可以实现高可用、高性能的目标。

缺点:死信队列本质还是一个队列,队列都是先进先出,如果队头的消息过期时间比较长,就会导致后面过期的消息无法得到及时消费,造成消息阻塞。

总结:除了增加系统复杂度之外,死信队列的阻塞问题也是需要我们重点关注的。

相关文章
|
15天前
|
负载均衡 Java Nacos
微服务架构中的服务注册与发现流程
本内容介绍了微服务架构中的服务注册与发现流程,包括服务注册中心(如Nacos)、服务提供者和调用者的角色分工。服务启动时自动注册信息至注册中心,调用者通过客户端负载均衡(如Spring Cloud Loadbalancer)选取服务实例进行远程调用。同时,内容还讲解了OpenFeign的工作原理,其作为HTTP客户端集成负载均衡,通过接口定义、代理生成、请求发送与结果解析,实现服务间的高效通信。
|
14天前
|
缓存 前端开发 Java
基于最新 Java 技术栈的在线任务管理系统开发实战详解
本项目基于最新Java技术栈开发在线任务管理系统,涵盖任务创建、分配、跟踪、统计等功能。采用Spring Boot 3.2.x、React 18、PostgreSQL 16等主流技术,详解项目架构设计、核心功能实现及部署流程,助力掌握现代Java全栈开发技能。
88 6
|
23天前
|
消息中间件 存储 前端开发
如何开发一套合同管理系统?(附架构图+流程图+代码参考)
合同管理系统是企业合同全生命周期管理的核心工具,涵盖合同创建、审批、执行、归档等环节,支持销售、采购、服务合同的统一管理。系统可实现收付款流程跟踪、发票管理及风险控制,避免手工管理的信息丢失与流程混乱问题。通过自动化与可视化手段,提升合同处理效率,优化财务流程,降低企业运营风险。
|
26天前
|
Cloud Native 测试技术 开发者
云原生 LFX Mentorship 招募中:开源影响力与丰厚报酬兼得,开发者不容错过!
参与其中的开发者不仅有机会在经验丰富的社区 Mentor 指导下贡献开源项目、为职业生涯加分,完成课题后还能获得丰厚酬劳。
|
11天前
|
传感器 人工智能 监控
戴手环太土了?皮肤植入式传感器才是健康监测的终极形态
戴手环太土了?皮肤植入式传感器才是健康监测的终极形态
73 12
|
19天前
|
Kubernetes 安全 Devops
「迁移急救包」全云平台无缝迁移云效实操手册
阿里云云效是国内领先的一站式DevOps平台,提供代码全生命周期管理、智能化交付流水线及精细化研发管控,支持多种开发场景。本文详细介绍了从其他平台(如Coding)向云效迁移的完整方案,包括代码仓库、流水线、制品仓库及项目数据的迁移步骤,帮助用户实现高效、安全的平滑迁移,提升研发效率与协作能力。
308 29
|
24天前
|
SQL 人工智能 JSON
Flink 2.1 SQL:解锁实时数据与AI集成,实现可扩展流处理
简介:本文整理自阿里云高级技术专家李麟在Flink Forward Asia 2025新加坡站的分享,介绍了Flink 2.1 SQL在实时数据处理与AI融合方面的关键进展,包括AI函数集成、Join优化及未来发展方向,助力构建高效实时AI管道。
344 43
|
15天前
|
算法 Java
Java语言实现链表反转的方法
这种反转方法不需要使用额外的存储空间,因此空间复杂度为,它只需要遍历一次链表,所以时间复杂度为,其中为链表的长度。这使得这种反转链表的方法既高效又实用。
69 0
|
15天前
|
存储 算法 Sentinel
熔断降级
本内容介绍了微服务中熔断降级的实现原理及Sentinel的底层机制。通过OpenFeign集成Sentinel,利用断路器统计异常和慢请求比例,触发熔断并降级,提升系统稳定性。还讲解了Sentinel使用的限流算法,如滑动窗口、令牌桶和漏桶算法,以应对不同场景下的流量控制需求。
|
13天前
|
人工智能 监控 算法
构建时序感知的智能RAG系统:让AI自动处理动态数据并实时更新知识库
本文系统构建了一个基于时序管理的智能体架构,旨在应对动态知识库(如财务报告、技术文档)在问答任务中的演进与不确定性。通过六层设计(语义分块、原子事实提取、实体解析、时序失效处理、知识图构建、优化知识库),实现了从原始文档到结构化、时间感知知识库的转化。该架构支持RAG和多智能体系统,提升了推理逻辑性与准确性,并通过LangGraph实现自动化工作流,强化了对持续更新信息的处理能力。
85 3