redis数据结构与应用场景

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis 是一款开源、免费的内存数据库,常用于处理高并发和大数据场景下的热点数据访问,以提升性能。它支持 key-value 存储及多种数据结构,如字符串、列表、集合和哈希表。数据可持久化到磁盘,与 MySQL 等传统数据库相比,Redis 作为缓存能提供更快的读写速度。Redis 应用场景包括:使用字符串进行计数(如商品库存、点赞数)、利用列表实现消息队列或展示最新商品、使用集合去重和计算交集等,以及通过有序集合进行自动排序(如商品热度榜)。

一、简介

Redis 是开源免费, key-value 内存数据库,主要解决高并发、大数据场景下,热点数据访问的性能问题,提供高性能的数据快速访问。项目中部分数据访问比较频繁,对下游 DB(例如 MySQL)造成服务压力,这时候可以使用缓存来提高效率。

Redis 的主要特点包括:

   Redis数据存储在内存中,可以提高热点数据的访问效率

   Redis 除了支持 key-value 类型的数据,同时还支持其他多种数据结构的存储;

   Redis 支持数据持久化存储,可以将数据存储在磁盘中,机器重启数据将从磁盘重新加载数据;

Redis 作为缓存数据库和 MySQL 这种结构化数据库进行对比。

   从数据库类型上,Redis 是 NoSQL 半结构化缓存数据库, MySQL 是结构化关系型数据库;

   从读写性能上,MySQL 是持久化硬盘存储,读写速度较慢, Redis 数据存储读取都在内存,同时也可以持久化到磁盘,读写速度较快;

   从使用场景上,Redis 一般作为 MySQL 数据读取性能优化的技术选型,彼此配合使用。Redis用于存储热数据或者缓存数据,并不存在相互替换的关系。

二、Redis 基本数据结构与实战场景

   redis的数据结构可以理解为Java数据类型中的Map<String,Object>,key是String类型,value是下面的类型。只不过作为一个独立的数据库单独存在,所以Java中的Map怎么用,redis就怎么用,大同小异。

   字符串类型的数据结构可以理解为Map<String,String>

   list类型的数据结构可以理解为Map<String,List<String>>

   set类型的数据结构可以理解为Map<String,Set<String>>

   hash类型的数据结构可以理解为Map<String,HashMap<String,String>>

上图中命令行更正:lrange,不是lrang

三、 redis应用场景解析

3.1 String 类型使用场景

场景一:商品库存数

从业务上,商品库存数据是热点数据,交易行为会直接影响库存。而 Redis 自身 String 类型提供了:

   incr key     #增加一个库存

   decr key    # 减少一个库存

   incrby key 10 # 增加20个库存

   decrby key 15   # 减少15个库存

   set goods_id 10; 设置 id 为 good_id 的商品的库存初始值为 10;

   decr goods_id; 当商品被购买时候,库存数据减 1。

依此类推的场景:商品的浏览次数,问题或者回复的点赞次数等。这种计数的场景都可以考虑利用 Redis 来实现。

场景二:时效信息存储

Redis 的数据存储具有自动失效能力。也就是存储的 key-value 可以设置过期时间,SETEX mykey 60 "value"中的第2个参数就是过期时间。

比如,用户登录某个 App 需要获取登录验证码, 验证码在 30 秒内有效。

   生成验证码:生成验证码并使用 String 类型在reids存储验证码,同时设置 30 秒的失效时间。如:SETEX validcode 30 "value"

   验证过程:用户获得验证码之后,我们通过get validcode获取验证码,如果获取不到说明验证码过期了。

3.2 List 类型使用场景

list 是按照插入顺序排序的字符串链表。可以在头部和尾部插入新的元素(双向链表实现,两端添加元素的时间复杂度为 O(1)) 。

场景一:消息队列实现

目前有很多专业的消息队列组件 Kafka、RabbitMQ 等。 我们在这里仅仅是使用 list 的特征来实现消息队列的要求。在实际技术选型的过程中,大家可以慎重思考。

list 存储就是一个队列的存储形式:

   lpush key value; 在 key 对应 list 的头部添加字符串元素;

   rpop key; 移除列表的最后一个元素,返回值为移除的元素。

场景二:最新上架商品

在交易网站首页经常会有新上架产品推荐的模块, 这个模块是存储了最新上架前 100 名。这时候使用 Redis 的 list 数据结构,来进行 TOP 100 新上架产品的存储。

Redis ltrim 指令对一个列表进行修剪(trim),这样 list 就会只包含指定范围的指定元素。

ltrim key start end

start 和 end 都是由 0 开始计数的,这里的 0 是列表里的第一个元素(表头),1 是第二个元素。

如下伪代码演示:

   //把新上架商品添加到链表里

   ret = r.lpush("new:goods", goodsId)

   //保持链表 100 位

   ret = r.ltrim("new:goods", 0, 99)

   //获得前 100 个最新上架的商品 id 列表

   newest_goods_list = r.lrange("new:goods", 0, 99)

3.3 set 类型使用场景

set 也是存储了一个集合列表功能。和 list 不同,set 具备去重功能(和Java的Set数据类型一样)。当需要存储一个列表信息,同时要求列表内的元素不能有重复,这时候使用 set 比较合适。与此同时,set 还提供的交集、并集、差集。

例如,在交易网站,我们会存储用户感兴趣的商品信息,在进行相似用户分析的时候, 可以通过计算两个不同用户之间感兴趣商品的数量来提供一些依据。

       //userid 为用户 ID , goodID 为感兴趣的商品信息。  

       sadd "user:userId" goodID

   

       sadd "user:101" 1

       sadd "user:101" 2

       sadd "user:102" 1

       Sadd "user:102" 3

   

       sinter "user:101" "user:102"    # 返回值是1

获取到两个用户相似的产品, 然后确定相似产品的类目就可以进行用户分析。类似的应用场景还有, 社交场景下共同关注好友, 相似兴趣 tag 等场景的支持。

3.4 Hash 类型使用场景

Redis 在存储对象(例如:用户信息)的时候需要对对象进行序列化转换然后存储,还有一种形式,就是将对象数据转换为 JSON 结构数据,然后存储 JSON 的字符串到 Redis。

对于一些对象类型,还有另外一种比较方便的类型,那就是按照 Redis 的 Hash 类型进行存储。

hset key field value

例如,我们存储一些网站用户的基本信息, 我们可以使用:

       hset user101 name "小明"

       hset user101 phone "123456"

       hset user101 sex "男"

这样就存储了一个用户基本信息,存储信息有:{name : 小明, phone : “123456”,sex : “男”}

当然这种类似场景还非常多, 比如存储订单的数据,产品的数据,商家基本信息等。大家可以参考来进行存储选型。但是不适合存储关联关系比较复杂的数据,那种场景还得用关系型数据库比较方便。

3.5 Sorted Set 类型使用场景

Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sorted set 可以通过提供一个 score 参数来为存储数据排序,并且是自动排序,插入既有序。业务中如果需要一个有序且不重复的集合列表,就可以选择 sorted set 这种数据结构。

比如:商品的购买热度可以将购买总量 num 当做商品列表的 score,这样获取最热门的商品时就是可以自动按售卖总量排好序。


相关文章
|
1月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
197 86
|
24天前
|
存储 消息中间件 NoSQL
Redis数据结构:别小看这5把“瑞士军刀”,用好了性能飙升!
Redis提供5种基础数据结构及多种高级结构,如String、Hash、List、Set、ZSet,底层通过SDS、跳表等实现高效操作。灵活运用可解决缓存、计数、消息队列、排行榜等问题,结合Bitmap、HyperLogLog、GEO更可应对签到、UV统计、地理位置等场景,是高性能应用的核心利器。
|
1月前
|
存储 缓存 NoSQL
Redis基础命令与数据结构概览
Redis是一个功能强大的键值存储系统,提供了丰富的数据结构以及相应的操作命令来满足现代应用程序对于高速读写和灵活数据处理的需求。通过掌握这些基础命令,开发者能够高效地对Redis进行操作,实现数据存储和管理的高性能方案。
76 12
|
1月前
|
存储 消息中间件 NoSQL
【Redis】常用数据结构之List篇:从常用命令到典型使用场景
本文将系统探讨 Redis List 的核心特性、完整命令体系、底层存储实现以及典型实践场景,为读者构建从理论到应用的完整认知框架,助力开发者在实际业务中高效运用这一数据结构解决问题。
|
1月前
|
存储 缓存 NoSQL
【Redis】 常用数据结构之String篇:从SET/GET到INCR的超全教程
无论是需要快速缓存用户信息,还是实现高并发场景下的精准计数,深入理解String的特性与最佳实践,都是提升Redis使用效率的关键。接下来,让我们从基础命令开始,逐步揭开String数据结构的神秘面纱。
|
11月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
914 9
|
11月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
237 59
|
4月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
75 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
363 77