基于 Redis 实现高性能、低延迟的延时消息的方案演进

news2024/9/23 19:23:10

1、前言

随着互联网的发展,越来越多的业务场景需要使用延迟队列。比如:

  • 任务调度:延时队列可以用于任务调度,将需要在未来某个特定时刻执行的任务放入队列中。消息延迟处理: 延时队列可以用于消息系统,其中一些消息需要在一段时间后才能被消费。例如,在需要进行消息重试的情况下,可以将消息放入延时队列,并在一段时间后重新处理订单处理:在电商系统中,有时需要对订单进行一些处理,例如取消未支付的订单或处理退货请求。
  • 会员到期提醒:如果你有一个会员制度,需要提醒会员其订阅即将到期,延时队列可以用于安排在到期日期前发送提醒通知。
  • 缓解高峰期负载:在高峰期,系统可能会面临大量的请求和负载。延时队列可以用于将一些请求推迟处理,进行削峰处理.

随着技术的进步,实现的方式也愈来愈多种多样,以 Java 语言为例,实现的方式也是多如牛毛,例如使用JDK字段得工具包实现;使用任务调度框架实现;使用Netty的时间轮询实现;使用消息队列实现;使用Redis 实现等等。本文主要探讨 Redis 实现延时消息的几种不同的方案演进。

2、技术方案

如前文所述,使用 Redis 来实现延时消息的实现方式主要有 3 种

  1. 过期事件监听
  2. Redis zset (有序集合)
  3. Redisson

得益于 Redis 自身设计的优点,使用 Redis 完全可以支撑高性能的要求。

从可靠性和使用便利性上来考虑,三种方案优先级排序: Redisson > zset> 过期事件监听

3、方案一: 过期事件监听

3.1 核心设计与原理

Redis 的过期事件监听是基于 pub/sub 的,key 过期时会 pub 消息到一个内置的 channel 中,客户端可以通过监听这个 channel 获取到消息,:进而实现延时队列的功能

3.2 方案缺陷

缺陷 1: 不支持持久化,可靠性低

pub/sub 模式下的过期事件监听,消息并不会做持久化,会有消息丢失的风险。

缺陷2:不保证及时性

过期事件监听的方案听起来很好理解,也似乎很完美,但事实并非如此。主要是借助 Redis 删除过期 key 的消息监听,不保证及时性

Redis 的单线程设计,如果需要支持定时过期,在 Redis 高负载的情况下或者有大量过期键需要同时处理时,会造成 Redis 服务器卡顿,影响主业务执行。考虑到可用性,Redis 的单线程机制并不能很好地支持定时删除过期 key 的场景,所以 Redis 使用惰性删除 + 定期删除key 的方式
也正因为 Redis key 的删除不是过期即删除的,所以 key 删除时发送消息的时间也不一定是 key的过期时间。

失效场景可以参考下图:

4、方案二: zset

Redis 提供了有序集合 zset,我们也可以利用 zset 封装延迟消息
zset 的常用命令及解释

ZADD key score member [score member ...]: 向有序集合 key 中添加一个或多个成员,每个成员都带有一个分值 score


ZRANGEBYSCORE key min max [WITHSCORES]: 返回有序集合 key 中分值介于 min 和 max 之间的成员。可选的 WITHSCORES 参数表示同时返回成员和分值


ZREM key member [member ...]: 从有序集合 key 中移除一个或多个成员

4.1 核心设计与原理

核心设计为使用 zset + 定时轮询器,基于 zset 的 ZRANGEBYSCORE 命获取已过期的延时任务,流程如下图所示:

4.2 方案缺陷

直接使用 zset 也存在一些端

缺陷 1: 额外的资源消耗

使用有序集合作为延时队列,并且需要定期地检查有序集合中的任务是否需要被处理,会占用CPU

资源2缺陷 2:使用上不够友好

需要自行封装,增加编码,在维护上增加了许多成本

5、方案三: Redisson

基于 4.2 小节的考虑,我们可以考虑使用 Redisson 提供的延时队列,它也是基于 zset 实现

5.1 核心设计与原理

Redisson 封装的延时队列源码还是蛮多的,限于篇幅,之后看情况再补充源码分析篇。本文只讲解源码核心链路的封装。

Redisson 封装了两个核心队列: RBlockingQueue 和 RDelayedQueue,其中 RDelayedQueue 作为中间队列,RBlockingQueue 作为目标消费队列。

5.2 方案优点

  1. 简单易用:可以通过注册监听的方式获取延时消息。
  2. 批量处理,低延迟: Redisson 延时队列使用定时任务进行批量处理,而不是每个任务都单独处理。这种批处理方式减少了与Redis的通信次数,提高了处理效率
  3. 异步处理: Redisson的延时队列支持异步任务处理,减少了等待时间和阻塞,提升了整体的吞吐量和响应性能。
  4. 支持分布式: Redisson的延时队列可以在分布式环境中使用,并提供了分布式锁和协调机制确保多个节点或实例之间的任务处理的一致性和可靠性。
  5. 延迟更低: Redisson 底层使用了 HashedWheelTimer,基于时间轮算法,具有高性能、较高精确度、内存友好、并发安全的特点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1397859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

beego的控制器Controller篇 — 错误处理

1 错误处理 在做 Web 开发的时候,经常需要页面跳转和错误处理,beego 这方面也进行了考虑,通过 Redirect 方法来进行跳转: func (this *AddController) Get() {this.Redirect("/", 302) } 如何中止此次请求并抛出异常…

基于ORB算法的图像匹配

基础理论 2006年Rosten和Drummond提出一种使用决策树学习方法加速的角点检测算法,即FAST算法,该算法认为若某点像素值与其周围某邻域内一定数量的点的像素值相差较大,则该像素可能是角点。 其计算步骤如下: 1)基于F…

Java 数组、二维数组、值传递和引用传递的区别

数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型。 即:数(数据)组(一组)就是一组数据。 数组是一种数据结构, 用来存储同一类型值的集合。通过一个整型下标可以访问数组中的每一个值。 数组的定义 在声明数组变量时&…

Unity—配置lua环境变量+VSCode 搭建 Lua 开发环境

每日一句:保持须臾的浪漫,理想的喧嚣,平等的热情 Windows 11下配置lua环境变量 一、lua-5.4.4版本安装到本地电脑 链接:https://pan.baidu.com/s/14pAlOjhzz2_jmvpRZf9u6Q?pwdhd4s 提取码:hd4s 二、高级系统设置 此电…

削峰填谷与应用间解耦:分布式消息中间件在分布式环境下并发流量控制的应用

这是《百图解码支付系统设计与实现》专栏系列文章中的第(18)篇,也是流量控制系列的第(4)篇。点击上方关注,深入了解支付系统的方方面面。 本篇重点讲清楚分布式消息中间件的特点,常见消息中间件…

二叉树的基础概念及遍历

二叉树(Binary Tree)的基础 1、树的概念 1、树的概念 树是一种非线性的数据结构,是由n(n>0)个有限结点组成一个具有层次关系的集合,将它称为树,是因为在形状上像一颗倒着的树,如下图所示就是一颗二叉…

Linux网络 ---- PXE高效批量网络装机

目录 一、系统装机 1、系统装机方式 2、系统装机的三种引导方式 3、系统安装过程 二、PXE原理和概念 1、PXE概述 2、搭建PXE网络体系所需条件 3、PXE批量部署的优点 4、PXE通常涉及以下几个组件: 5、PXE实现过程详细 三、搭建过程 1、搭建过程服务详解 …

【SpringBoot】SpringBoot 项目初始化方法

github 搜索 springboot 模板 github 搜索 springboot 模板,拉取现成代码。 SpringBoot 官方的模板生成器 SpringBoot 官方的模板生成器(https://start.spring.io/) 在 IDEA 开发工具中生成 这里我修改成阿里的镜像主要是要使用 Java8。 …

分库分表场景分析

背景:目前需支撑交易表日五千万数据,后续完全切量到此新系统 数据库:四个部署在Aix系统上的Oracle库、每个库一张交易主表(按日31个物理分区)、十二个交易历史表(无分区) 服务节点:每个Oracle库都对应着多…

Git 配置与理解

简述 Git 在 Windows 和 Ubuntu 中的配置,以及对 Git 工作区域划分和 Git 中对于文件状态划分的理解。 git 基础安装与配置 基于 WSL 的 Ubuntu 下的 git 打开或关闭Windows功能 -> Hyper-V、Virtual Machine Platform、Windows Subsystem for Linux # 1.必须…

2023 IoTDB Summit:湖南大唐先一科技有限公司主任架构师舒畅《IoTDB 在发电领域的应用实践》...

12 月 3 日,2023 IoTDB 用户大会在北京成功举行,收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题,多位学术泰斗、企业代表、开发者,深度分享了工业物联网时序数据库 IoTDB 的技术创新…

高清网络视频监控系统技术方案

目 录 一、概述 二、建设目标及需求 (一)建设总目标 (二)需求分析 三、设计依据与设计原则 (一)设计依据 (二)设计原则 四、建设方案设计 (一&…

浪花 - 用户信息展示+更新

1. 用户登录获取登录凭证 已登录的用户才能获取个人信息发送 Aixos 请求登录 const user ref();onMounted(async () > {const res await myAxios.get(/user/current);if (res.code 0) {console.log("获取用户信息成功");user.value res.data;} else {consol…

进入docker容器,vi: command not found

问题描述: 进入docker容器,查看文件执行vim 命令,报错 vim: command not found。搜索解决方案,说执行一下 apt-get install vim命令,然后又报错 Unable to locate package vim。 解决: 1.执行 npt-get up…

亚马逊云科技 WAF 部署小指南(六)追踪 Amazon WAF Request ID,排查误杀原因

众所周知,中国是全球制造业的巨大力量,许多中国企业通过 2B 电商平台网站进行商品销售和采购。在这些电商平台上,Web 应用防火墙(WAF)成为不可或缺的安全工具。然而,WAF 也可能导致误杀问题。一旦误杀发生&…

Deep MultimodalLearningA survey on recent advances and trends

深度多模态学习:对近期进展和趋势的综述 深度学习的成功已经成为解决越来越复杂的机器学习问题的催化剂,这些问题通常涉及多个数据模态。我们回顾了深度多模态学习的最新进展,并突出了该活跃研究领域的现状,以及存在的差距和挑战…

Java中打印图案最常用的25个图案程序

Java是公认的最流行的编程语言,因为它的简单性和多功能性。还可以使用它开发各种应用程序,包括Web、移动和桌面应用程序。此外,Java为开发人员提供了强大的工具来轻松高效地创建复杂的程序。Java最有前途的特性之一是它能够创建可以以特定格式…

爬虫-selenium自动化(3)-验证码

#验证码分很多种,奇葩也无处不在:哪个是真茅台,红绿灯,摩托车......(我是个人都看不出来) (๑﹏๑) #本节内容为selenium自动化实现验证码通过-------字符验证码,点触验证码。 验证码介绍 字符验证码案例 点触验证码案例

[Python] scikit-learn之mean_squared_error函数(Mean Squared Error(MSE))介绍和使用案例

什么是均方误差(MSE)和均方根误差(RMSE)? MSE 是均方误差(Mean Squared Error)的缩写,是一种常用的衡量回归模型预测精度的指标。它表示预测值与真实值之间差异的平方和的平均值,通常用于评估回归模型的性能。 RMSE 是均方根误差(Root Mean Squared Er…

C#,字符串匹配(模式搜索)有限自动机(Finite Automata)算法的源代码

一、有限状态自动机 图中两个圆圈,也叫节点,用于表示状态,从图中可以看成,它有两个状态,分别叫0和1。从每个节点出发,都会有若干条边。当处于某个状态时,如果输入的字符跟该节点出发的某条边的内…