当前位置: 首页 > article >正文

Redis中的数据结构

1.五种常见的数据结构类型

1. 字符串(String)

特点

  • 字符串是 Redis 最基本的数据类型,可以存储字符串整数浮点数
  • 一个字符串最多可以存储 512 MB 的数据。

使用场景

  • 缓存简单数据:比如存储用户的登录状态、会话信息或配置信息。
  • 计数器:字符串支持自增和自减,可以方便地用来实现计数器,如网站访问次数统计。
  • 分布式锁:通过 SETNX 命令可以实现分布式锁。

2. 列表(List)

特点

  • 列表是一个有序的字符串序列,可以从两端添加移除元素
  • 支持常见的队列操作(如 LIFO 和 FIFO)。

使用场景

  • 消息队列:列表支持从头部或尾部推入和弹出元素,因此常用于简单的消息队列。
  • 任务列表:可以用来存储一系列需要按顺序处理的任务。
  • 时间轴:社交媒体的时间轴可以用列表来实现,记录用户的操作历史等。

3. 集合(Set)

特点

  • 集合是无序且唯一的字符串集合,元素不重复。
  • 支持交集、并集和差集等集合运算。

使用场景

  • 标签和关注关系:如用于存储用户的关注列表、标签等,避免重复。
  • 抽奖系统:用户抽奖时,可以使用集合确保每位用户只参与一次。
  • 共同好友推荐:通过交集运算,找出两个用户共同关注的好友。

4. 有序集合(Sorted Set)

特点

  • 有序集合中的每个元素都有一个分数(score),Redis 会根据分数对元素进行排序。
  • 支持按分数范围查询元素,也可以按分数排名来访问元素。

使用场景

  • 排行榜:常用于实现游戏或应用的排行榜,按得分高低排序。
  • 任务调度:可以根据任务的优先级来安排执行顺序。
  • 带权重的数据:例如评分系统,可以根据评分来展示内容的排名。

5. 哈希(Hash)

特点

  • 哈希是一个键值对集合,适合存储对象或数据结构。
  • 可以把多个字段及其值存储在一个键下,通过字段名称快速访问字段的值。

使用场景

  • 用户信息存储:可以用来存储用户信息(如用户名、年龄、地址等),并快速访问特定字段。
  • 缓存对象数据:适合存储一些需要快速访问的对象或数据结构。
  • 配置项管理:适合存储分模块的配置信息。

类型对比

数据类型是否有序是否唯一适用场景
字符串简单数据、计数器、锁
列表消息队列、任务列表
集合标签、抽奖系统
有序集合排行榜、带权重数据
哈希用户信息、配置项

2.后续引入的四种数据类型

1. BitMap

版本

  • Redis 2.2 版引入。

特点

  • BitMap 并不是 Redis 独立的数据类型,而是一种基于字符串类型的位操作方法
  • BitMap 允许我们将一个大的字符串值视为一系列的位(bit),并可以对每一位进行单独操作
  • BitMap 中的每一位可以是 0 或 1,能高效地进行位操作,例如设置某一位的值获取某一位的值,或者统计多个位中的 1 的个数

使用场景

  • 用户签到:可以用一个 BitMap 表示每个用户在一年中的签到情况。假设有 365 天,用 365 位表示即可。
  • 活跃用户统计:在每一位表示一个用户的活跃状态,0 表示不活跃,1 表示活跃。通过位操作快速统计活跃用户。
  • 二进制标记:用于对大量用户的某些特定标记进行标识和统计。

示例

假设我们想记录一个用户在一个月中的签到情况,可以用 BitMap 操作设置某天为签到:

# 设置用户在第 5 天签到
SETBIT user:1001:checkin 5 1
# 获取用户第 5 天的签到状态
GETBIT user:1001:checkin 5  # 返回 1
# 统计这个用户的签到天数
BITCOUNT user:1001:checkin

2. HyperLogLog

版本

  • Redis 2.8 版引入。

特点

  • HyperLogLog 是一种基数估计算法,可以高效地计算大规模数据的基数(独特元素的数量)。
  • HyperLogLog 的存储空间是固定的,只占用 12 KB 内存,即使是十亿级的去重数据,也不会增加内存占用。
  • HyperLogLog 通过概率算法近似计算基数,因此有误差(标准误差约 0.81%),但通常可接受。

使用场景

  • UV(独立访问用户)统计:在大数据量的情况下,用 HyperLogLog 统计页面的独立访问用户数量。
  • 去重计数:如在电商网站中统计特定时间内访问商品详情页的独立用户数,HyperLogLog 非常适合这种场景。

示例

使用 HyperLogLog 统计每天访问某网站的用户数量:

# 将用户 ID 添加到 HyperLogLog
PFADD page:1001:user_set user1 user2 user3
# 获取 HyperLogLog 基数
PFCOUNT page:1001:user_set  # 返回基数估算值
# 合并多个 HyperLogLog 的基数
PFMERGE combined_users page:1001:user_set page:1002:user_set

3. GEO

版本

  • Redis 3.2 版引入。

特点

  • GEO 是 Redis 的地理位置数据类型,基于有序集合实现,能够存储地理位置信息(经纬度)并支持地理操作。
  • Redis 提供了一系列 GEO 命令,如添加位置计算两地距离查询指定范围内的位置等。

使用场景

  • 附近的人:在社交或打车应用中,可以快速查找某个范围内的用户或服务提供者。
  • POI(兴趣点)查询:例如餐馆、加油站等可以存储在 Redis 中,用户可以根据当前地点查询附近的 POI。

示例

假设我们要在 Redis 中存储和查询城市的地理位置:

# 添加地理位置(城市名称和经纬度)
GEOADD cities 13.361389 38.115556 "Palermo"
GEOADD cities 15.087269 37.502669 "Catania"

# 查询两个城市之间的距离
GEODIST cities "Palermo" "Catania" km  # 返回距离,单位为公里

# 获取指定地点附近的城市
GEORADIUS cities 15 37 200 km  # 返回 200 公里范围内的地点

4. Stream

版本

  • Redis 5.0 版引入。

特点

  • Stream 是一种可无限增长的日志结构数据类型,支持队列和发布-订阅模式,适合处理实时数据流。
  • Stream 提供了对消息的追加读取分组消费等操作,并可以按 ID 或时间戳查询数据。
  • Stream 支持消费者分组,允许不同消费者组读取相同的数据流。

使用场景

  • 日志和事件存储:可以用于存储系统日志、用户行为数据等,可以在需要时实时读取。
  • 消息队列:Stream 的消费者分组特性使其适合构建简单的消息队列系统。
  • 实时数据处理:如 IoT 设备传回的数据流处理,Redis Stream 可以充当数据缓冲区。

示例

使用 Stream 存储和读取事件:

# 添加一条新事件(Stream 会自动生成 ID)
XADD mystream * temperature 22.5 humidity 60

# 读取最新的事件
XRANGE mystream - +  # 返回按时间排序的所有事件

# 创建消费者组
XGROUP CREATE mystream mygroup $  # $ 表示从最新消息开始消费

# 消费者组读取消息
XREADGROUP GROUP mygroup consumer1 COUNT 2 STREAMS mystream >

类型对比

数据类型引入版本特点使用场景
BitMap2.2位操作,高效标记和统计用户签到、活跃用户统计
HyperLogLog2.8基数估计,固定存储UV统计、大数据去重计数
GEO3.2地理位置存储和查询附近的人、POI查询
Stream5.0实时数据流、消费者分组消息队列、实时数据处理

3.五种常见数据类型的实现

1. 字符串(String)

实现方式

  • Redis 的字符串是最基础的数据类型,主要是用简单动态字符串(SDS)来实现的。SDS 是一种类似于 C 语言的字符串,但在结构和管理方式上更为灵活。
  • SDS 包括两部分:实际存储的字符串内容长度信息,其中长度信息可以让 Redis 快速获取字符串长度。

结构细节

  • 空间管理:SDS 会自动扩容。比如新增内容超出当前空间时,SDS 会一次性增加空间,减少多次扩容带来的开销。
  • 安全性:SDS 不用像 C 字符串那样依赖终止符 \0。它能直接记录长度,避免越界问题。
  • 灵活性:SDS 允许存储二进制数据,可以不仅仅是字符串,甚至可以存放图片、视频等。

内部操作

  • Redis 会根据字符串的长度自动选择存储形式,比如短字符串直接存储,而长字符串可以使用压缩或对象来节省内存。

2. 列表(List)

实现方式

Redis 的列表有两种实现结构:

  • 双向链表(Linked List):当列表元素较少且不需要快速访问时,Redis 会使用双向链表。这种结构非常适合频繁在两端插入和删除元素的场景。
  • 紧凑列表(ziplist):当列表的元素数量少或数据量不大时,Redis 使用压缩存储的 ziplist,它将所有元素压缩成一个连续的内存块。这样不仅节省空间,还能加速遍历。

结构细节

  • 双向链表:每个节点包含指向前后两个节点的指针,因此可以从两端快速插入和删除。双向链表适合处理大型列表或频繁插入删除操作。
  • 紧凑列表:由于没有指针,节省了空间,并且通过连续的内存区域存储元素,提高了读取效率。但随着元素变多,ziplist 的插入和删除会变慢。

内部操作

  • Redis 会根据列表的元素数量和大小动态选择链表或紧凑列表作为实现。比如,当元素很少且较小时,使用 ziplist;反之则使用双向链表。

3. 集合(Set)

实现方式

Redis 的集合有两种实现:

  • 字典(hash table):当集合中的元素较多时,Redis 使用哈希表来存储。哈希表的结构允许快速增删查改元素。
  • 整数集合(intset):当集合中的元素数量少并且全为整数时,Redis 会使用 intset 存储。整数集合通过连续的内存区域存储每个整数,适合小型集合。

结构细节

  • 字典:使用哈希表存储,每个元素的值通过散列函数分布在不同的桶中,可以快速进行查找、插入和删除。
  • 整数集合:是一种小而紧凑的数据结构,特别适合存储小数量的整数集合。通过二分查找提高查询速度。

内部操作

  • Redis 会根据集合的大小和内容类型选择合适的数据结构。开始时如果集合小且是整数,就使用整数集合;随着数据的增加或类型变化,再切换到哈希表。

4. 有序集合(Sorted Set)

实现方式

有序集合通过跳表(skip list)和哈希表结合来实现。

  • 跳表:是一种分层链表结构,允许元素在链表中分层跳跃,从而实现高效的增删查操作。
  • 哈希表:用来实现元素值到分数的快速映射。

结构细节

  • 跳表的实现:有序集合中的每个元素都被存储在跳表中,跳表的每一层可以包含多个节点,而高层节点更少,使得查找效率接近于二分查找。
  • 哈希表的作用:哈希表帮助 Redis 快速定位元素,确保在修改或删除元素时,跳表和哈希表同步更新。

内部操作

  • 跳表的主要作用是保持元素按分数排序,而哈希表则帮助 Redis 快速访问元素分数。通过两者的结合,有序集合既支持快速查询特定分数的元素,又能按分数排序输出。

5. 哈希(Hash)

实现方式

Redis 的哈希表使用两种结构:

  • 压缩列表(ziplist):当哈希表的字段少且数据量小,Redis 使用 ziplist 存储,这样可以节省内存空间。
  • 字典(hash table):当哈希表字段多时,Redis 使用哈希表来实现,便于快速查找和更新。

结构细节

  • 压缩列表:ziplist 把字段和值紧凑存储在一个连续的内存区域,适合小型哈希表。这样存储的方式减少了内存碎片,但不适合频繁插入和删除。
  • 哈希表:当哈希表变大或数据复杂时,Redis 转为用哈希表来管理。这种结构有助于快速访问每个字段。

内部操作

  • Redis 会根据哈希表的大小选择合适的实现。如果字段较少则用压缩列表,而随着字段增多或变大,则切换为哈希表,从而提升效率。

总结

数据类型实现结构适用场景
字符串SDS简单字符串存储、计数器等
列表双向链表/紧凑列表消息队列、任务列表等
集合哈希表/整数集合去重、标签管理等
有序集合跳表+哈希表排行榜、优先级队列等
哈希压缩列表/哈希表用户信息存储、对象属性管理等

        Redis 的这种“结构适应性”设计,让它可以根据数据特点自动调整底层实现,在保证数据存储灵活性的同时,保持高效的查询和操作速度。


http://www.kler.cn/a/385478.html

相关文章:

  • Select,poll,epoll和IO多路复用和NIO
  • S32G-VNP-RDB2开发环境搭建
  • Java 类加载机制详解
  • HTML 基础架构:理解网页的骨架
  • Java集合框架之映射(Map)
  • 全球海工供应链,中国建造!第十一届全球FPSOFLNGFSRU大会在上海隆重召开
  • oracle字符集的使用(修改字符集可能导致索引失效)
  • QT创建mainWindow窗口组件
  • 高校宿舍信息管理系统小程序
  • ubuntu22.04 密钥存储在过时的 trusted.gpg 密钥环中
  • 验证码-滑动验证码和点选验证码
  • uniapp发布到微信小程序,提示接口未配置在app.json文件中
  • YAML 语法随笔
  • 微软日志丢失事件敲响安全警钟
  • SQLI LABS | Less-35 GET-Bypass Add Slashes (we dont need them) Integer Based
  • 2024中国国际数字经济博览会:图为科技携明星产品引领数智化潮流
  • 在 Sass 中使用 Mixins
  • 基于Scikit-learn的多元线性回归模型构建与验证
  • 鸿蒙进阶篇-网格布局 Grid/GridItem(二)
  • LeetCode题练习与总结:打乱数组--384
  • 无人机干扰与抗干扰,无人机与反制设备的矛与盾
  • 如何解决导入aioredis报错TypeError: duplicate base class TimeoutError的问题(轻松解决,亲测有效)
  • 可视化建模与UML《类图实验报告》
  • WebRTC 环境搭建
  • 【报错解决】使用@SpringJunitConfig时报空指针异常
  • huawei初级网络工程师综合实验