Redis 给集合元素单独设置过期

其他系列文章导航

Java基础合集
数据结构与算法合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、场景

1.1 消费队列

1.2 Redis实现

二、常见的方案

2.1 为单独的 field 设置过期

2.2 设置整体过期时间

2.3 zset 结合 score实现

2.4 底层实现

2.4.1 ZipList 实现

2.4.2 SkipList 实现 

2.5 代码实现

三、总结


前言

Redis 是一个开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理。

在 Redis 中,集合(Set)是一种无序的数据类型,用于存储不重复的字符串元素。

虽然 Redis 的集合本身不支持为每个元素单独设置过期时间,但你可以通过一些技巧和策略来实现类似的功能。


一、场景

1.1 消费队列

最近,朋友在使用 Redis 时,脑中闪过一个创新的想法。他想用 Redis 的基础数据结构来构建一个简单版的延迟消费队列。

对于这个业务需求,我们需要设计一个状态图:

同时,我们需要确保队列的长度始终处于控制之中,例如,我们只允许用户拥有最多3个未支付的订单。

1.2 Redis实现

Redis,这款高性能的缓存和数据存储数据库,已经成为了后台开发者的得力助手。

假如我们要用 Redis 作为消费队列,我们可以考虑使用 List、Hash 和 Set 这三种数据结构。在这个业务场景中,由于我们主要关注的是 orderId(订单 ID),所以这三种数据结构都可以满足我们的需求。

例如,使用 hash 数据结构来存储数据时,我们可以设置 key 为 UnpaidOrder-{userId},然后每个 field 对应一个订单。

然而,现在我们面临一个挑战:每个订单的存活时间不同,有手动消费和定期删除两种逻辑。

  • 订单1,如果手动支付,需要从列表中删除 orderId1;
  • 订单2,如果在半小时内未支付,就会自动过期,用户还可以继续提交订单到未支付状态。

这就意味着在 List、Set 或者 Hash 这三种结构中,每个 field 都需要设置单独的过期时间。

这是一个常见而又棘手的问题,本文将从互联网业务中常见的解决方案入手,深入探讨一下 Redis 的底层实现。


二、常见的方案

在开发过程中,我们经常会遇到一种情况:需要计算某些特定字段的数量,而这些字段的生存时间又各不相同。

比如说,我们需要在业务中计算用户的未支付订单数,但是每个订单的过期时间都不相同。

在这种情况下,我们需要手动删除已经过期的字段,或者设置它们自动过期。

2.1 为单独的 field 设置过期

Redis 里面暂时没有接口给 List、Set 或者 Hash 的 field 单独设置过期时间,只能给整个列表、集合或者 Hash 设置过期时间。

这样,当 List/Set/Hash 过期时,里面的所有 field 元素就全部过期了

但这样并不满足需求。

除非你同时把 field 和过期时间都存下来,然后在程序里面判断它是否过期。

2.2 设置整体过期时间

我们首先可以考虑给整个 List/Set/Hash 设置过期时间。

这很难满足每个字段单独设置过期时间的需要。

既然每个订单的过期时间都不同,我们是否可以根据时间来创建不同的集合,将同一时间过期的订单放在同一个集合中:

然后,我们可以分别为不同的集合设置 TTL。当订单过期未支付时,订单会随着集合的过期而在同一分钟内被删除。

然而,这种方法也存在一些问题。每次新增订单时,我们需要遍历过去30分钟的集合,检查是否有该用户的订单,并判断用户的未支付订单数是否超限。

此外,按分钟创建集合可能存在一个问题:用户的订单可能在01秒就过期了,但在59秒才被删除。

如果按秒创建集合,30分钟将需要创建1800个集合,这使得管理变得更加困难。因此,为集合设置整体过期时间并不是一个可行的解决方案。

2.3 zset 结合 score实现

除了常见的 List/Set/Hash 结构,Redis 还拥有一个专门用于排序的数据结构 zset(Sorted Set,排序集合)。

基于 Redis 的 Zset 结构,我们可以利用 Score 来表示过期时间,从而轻松实现每个字段的独立过期。

具体实现方法如下:

  1. 每次新增待支付订单时,我们将当前时间的 Unix timestamp 加上过期时间 30min 作为 score 设置为该元素。这样,sorted set 会根据这个过期时间戳对元素进行排序和存储。
  2. 当订单被支付后,根据 userId 和 orderId 删除 sorted set 中的待支付订单。
  3. 同时,在程序中添加一个定时任务,每隔一秒删除当前时间已过期的订单。

2.4 底层实现

用 Redis 的 zset 一方面可以很方便地实现了对每个字段的单独过期,不再受整个 Key 的过期时间限制,提高了灵活性。

另一方面,Redis 的 zset 操作是十分高效的,不会给系统带来显著的性能压力。

这得益于 zset 底层的数据结构,Zset 底层实现采用了 ZipList(压缩列表)和 SkipList(跳表)两种实现方式,当满足:

  • Zset 中保存的元素个数小于 128(可通过修改 zset-max-ziplist-entries 配置来修改)

  • Zset 中保存的所有元素长度小于 64byte(通过修改 zset-max-ziplist-values 配置来修改)

两个条件时,Zset 采用 ZipList 实现;否则,用 SkipList 实现。

2.4.1 ZipList 实现

ZipList 是一个数组的形式,存储数据时分为列表头部分和数据部分,列表头部分有 3 个元素:

  • zlbytes:表示当前 list 的存储元素的总长度

  • zllen:表示当前 list 存储的元素的个数

  • zltail:表示当前 list 的头结点的地址,通过 zltail 就是可以实现 list 的遍历

数据部分以键值对的方式依次排列,键存储的是实际 member,值存储的是 member 对应的分值(score)。

2.4.2 SkipList 实现 

SkipList 分为两部分:

  1. dict 部分是由字典实现(其实就是 HashMap,里面放了成员到 score 的映射);

  2. zset 部分使用跳跃表实现(存放了所有的成员,解决了 HashMap 中 key 无序的问题)。

从图中可以看出,dict 和 zset 都存储数据。

但实际上 dict 和 zset 最终使用的指针都指向了同一份成员数据,即数据是被两部分共享的,为了方便表达将同一份数据展示在两个地方。

2.5 代码实现

当我们插入一个过期时间到 zset 时,Redis 会自动帮我们排好序,我们只需要在程序中新增一个定时任务,比如:每秒执行一次删除任务,删除时间戳从 0 到当前时间戳的 score 值即可

伪代码如下:

# 1. 创建新的待支付订单时,查询zset个数
count = zcard UnpaidOrder-{userId}

# 2. 判断未支付订单个数
if count >= 3:
    return

# 3. 新增订单
zadd UnpaidOrder-{userId} redis.Z{Score: {timestamp1}, Member: {order1}}

# 4.1 订单支付后,从 set 中删除未支付订单
zrem UnpaidOrder-{userId} order1

# 4.2 过期时间到了,从 set 中删除未支付订单
zremrange UnpaidOrder-{userId} 0 {current_timestamp}

三、总结

通过合理的数据结构选择和巧妙的应用,我们成功地解决了为 List、Set 和 Hash 结构中的字段设置单独过期时间的问题。

这个方案在实际项目中得到了验证,并取得了显著的效果。

对比其它的延时队列,或者 etcd 的 field 过期方案,Redis 的实现相对而言更为便捷,理解起来也更为简单。


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

项目实战:数字孪生可视化大屏幕,实现生产过程实时监控

项目介绍 智慧工厂数据可视化系统,融合工业大数据、物联网、人工智能等各类信息技术,整合厂区现有信息系统的数据资源,实现数字孪生工厂、设备运维监测、智能管网监测、综合安防监测、便捷通行监测、能效管理监测、生产管理监测、仓储物流监…

【数据分析实战】冰雪大世界携程景区评价信息情感分析采集词云

文章目录 引言数据采集数据集展示数据预处理 数据分析评价总体情况分析本人浅薄分析 各游客人群占比分析本人浅薄分析 各评分雷达图本人浅薄分析 差评词云-可视化本人浅薄分析 好评词云-可视化本人浅薄分析 综合分析写在最后 今年冬天,哈尔滨冰雪旅游"杀疯了&q…

技术学习|CDA level I 业务分析方法

业务分析方法有三个主要构成部分:业务指标分析、业务模型分析及业务分析方法。 业务指标分析是发现业务问题的核心方法:用于通用指标和场景指标的计算及分析方法,以及指标体系的设计与应用方法。业务模型是从一系列业务行为中抽象出来的信息…

请你列出逻辑电路中的24种表达式

随着时代发展,数字电路的使用频率越来越高,完全不低于模拟电路,因此从事数字电路的工程师越来越多,如果你想成为一名优秀的数字工程师,一定要学会下面的逻辑电路表达式! 1、基本逻辑运算与运算 (AND): A AN…

04 帧 Frame

文章目录 04 帧 Frame4.1 相机相关信息4.2 特征点提取4.2.1 特征点提取 ExtractORB()4.3 ORB-SLAM2对双目/RGBD特征点的预处理4.3.1 双目视差公式4.3.2 双目图像特征点匹配 ComputeStereoMatches()4.3.3 根据深度信息构造虚拟右目图像:ComputeStereoFromRGBD() 4.4 …

Python中的h5py包使用

h5py是一个非常强大的工具,可以用于存储和处理大量科学数据。它可以帮助我们提高数据处理的效率和可靠性。 目录 一、h5py1.1 特点1.2 主要功能1.3 常用场景 二、安装h5py三、示例代码3.1 运行结果 四、总结 一、h5py h5py是Python中的一个库,提供了对H…

JS函数实现数字转中文大写

JS函数实现数字转中文大写 1. 数字转字符,分割,去除空字符2. 遍历分割字符,替换为中文3. 增加四位数单位4. 处理零5. 拼接四位数据和单位 项目中,JS将万亿以下正整数转为中文大写 1. 数字转字符,分割,去除空字符 function toChineseNumber(num){const strs num.toString().re…

计算机组成原理 总线

总线 总线定义 总线 总线是一组能为多个部件分时共享的公共信息传送线路 总线的好处 早期计算机外部设备少时大多采用分散连接方式,不易实现随时增减外部设备 为了更好地解决I/O设备和主机之间连接的灵活性问题,计算机的结构从分散连接发展为总线连接 …

Mac环境下Parallels Desktop 19的安装和使用

为了后续构建漏洞靶场和渗透测试环境,我们需要提前准备好几套与宿主机隔离的工作环境(Windows、Linux等),在Mac上最常用的就是Paralles Desktop(PD)工具了,当前最新版本为19。接下来介绍如何安装…

QT工具栏开始,退出

QT工具栏开始,退出 //初始化场景QMenuBar *bar menuBar();setMenuBar(bar);QMenu *startbar bar->addMenu("开始");QAction * quitAction startbar->addAction("退出");connect(quitAction , &QAction::triggered,[](){this->c…

Chromedriver 下载和安装指南

1. 确定Chrome浏览器版本 首先,在谷歌浏览器中找到当前版本信息。 打开“设置”,点击“关于谷歌”即可看到版本号。确保后续下载的Chromedriver版本与Chrome浏览器版本一致。或者直接跳转网页地址:chrome://settings/help 2. 下载Chromedri…

js逆向第12例:猿人学第5题js混淆-乱码增强

文章目录 那么`RM4hZBv0dDon443M=`是怎么来的?密钥怎么找加密数组怎么破解_0x4e96b4[_$pr]m=,f=时间戳是哪个?打开控制台查看数据接口 https://match.yuanrenxue.cn/api/match/5?page=2&m=1704439385499&f=1704439384000 利用postman测试接口请求,判断参数是否强…

机器学习 - 决策树

场景 之前有说过k近邻算法,k近邻算法是根据寻找最相似特征的邻居来解决分类问题。k近邻算法存在的问题是:不支持自我纠错,无法呈现数据格式,且吃性能。k近邻算法的决策过程并不可视化。对缺失数据的样本处理很不友好,…

C++ OpenGL 3D GameTutorial 1:Making the window with win32 API学习笔记

视频地址https://www.youtube.com/watch?vjHcz22MDPeE&listPLv8DnRaQOs5-MR-zbP1QUdq5FL0FWqVzg 一、入口函数 首先看入口函数main代码&#xff1a; #include<OGL3D/Game/OGame.h>int main() {OGame game;game.Run();return 0; } 这里交代个关于C语法的问题&#x…

MidJourney笔记(10)-faq-fast-help-imagine-info-public-stealth

/faq 在官方 Midjourney Discord 服务器中使用可快速生成流行提示工艺频道常见问题解答的链接。 不过这个命令,我也是没有找到入口,之前还能在MidJourney的频道里使用,然后最近发现没有权限,有点奇怪。不知道系统又做了什么升级。 /fast 切换到快速模式。

七、HTML 文本格式化

一、HTML 文本格式化 加粗文本斜体文本电脑自动输出 这是 下标 和 上标 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>HTML文本格式化</title> </head><body><b>加粗文本</b><br>…

HarmonyOS应用开发学习笔记 包名、icon图标,应用名修改 UIAbility组件介绍、UIAbility启动模式、UIAbility组件基本用法

目前HarmonyOS应用主推的是Stage模型开发 一、Stage模型基本概念 项目描述UIAbility组件UIAbility组件是一种包含UI界面的应用组件&#xff0c;主要用于和用户交互。例如&#xff0c;图库类应用可以在UIAbility组件中展示图片瀑布流&#xff0c;在用户选择某个图片后&#xf…

Mysqld的关键优化参数

skip-name-resolve 现象 mysql连接很慢&#xff0c;登陆到服务器上查看服务器日志都是正常的&#xff0c;无可疑记录&#xff0c;登陆到mysql服务器上&#xff0c;查看下进程&#xff0c;发现有很多这样的连接&#xff1a; 218 | unauthenticated user | 192.168.10.6:44500 |…

Stable Diffusion架构的3D分子生成模型 GeoLDM - 测评与代码解析

之前&#xff0c;向大家介绍过3D分子生成模型 GeoLDM。 GeoLDM按照Stable Diffusion架构&#xff0c;将3D分子生成的扩散过程运行在隐空间内&#xff0c;优化了基于扩散模型的分子生成。可能是打开Drug-AIGC的关键之作。让精确控制分子生成有了希望。 详见&#xff1a;分子生成…

听GPT 讲Rust源代码--compiler(16)

File: rust/compiler/rustc_span/src/lib.rs 在Rust源代码中&#xff0c;rust/compiler/rustc_span/src/lib.rs文件定义了与Rust编译器源代码位置相关的数据结构和功能。 下面是对一些重要结构和枚举类型的详细介绍&#xff1a; SessionGlobals: 代表编译器会话&#xff08;Ses…
最新文章