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

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) 实现字符串类型。
  • 结构
    • len:记录字符串的实际长度,避免每次操作都需要重新计算长度。
    • alloc:记录已分配的空间大小,方便动态扩展。
    • buf:用于存储字符串数据的实际内容。
  • 特点
    • 预分配空间:SDS 扩展空间时会预留一些额外空间,减少扩展操作的频率。
    • 惰性空间释放:在缩短字符串时,直接更新 len,而不立即释放多余内存,减少频繁内存重分配操作。
  • 适用场景:适合存储单个字符串数据、整数、浮点数等简单数据,支持 512 MB 以内的内容。

2. 列表(List)

  • 实现方式:Redis 使用 双向链表(quicklist)压缩列表(ziplist) 来实现列表类型。
  • 结构
    • Quicklist:一种特殊的双向链表结构,结合了链表和压缩列表。链表节点存储压缩列表,支持快速的头部和尾部插入、删除操作。
    • Ziplist:连续内存存储的小型双向链表,适用于少量短字符串的列表,减少内存开销。
  • 特点
    • 高效插入和删除:Quicklist 支持快速的头部和尾部操作,适合频繁的增删操作。
    • 内存优化:当数据量小且节点较少时,压缩列表减少内存消耗。
  • 适用场景:适合存储有序的字符串序列,通常用于消息队列或任务队列等需要顺序访问的场景。

3. 集合(Set)

  • 实现方式:Redis 使用 整数集合(intset)哈希表(hashtable) 来实现集合类型。
  • 结构
    • Intset:连续存储的整数集合,适用于只包含整数且元素数量较少的集合。
    • Hashtable:包含更多元素或非整数元素时使用哈希表,以保证插入和查找的效率。
  • 特点
    • 高效查找和去重:哈希表结构能够快速判断元素是否存在。
    • 内存优化:小型整数集合使用 intset 节省内存。
  • 适用场景:适合需要快速查重和集合操作的场景,如标签、用户权限管理等。

4. 有序集合(Sorted Set)

  • 实现方式:Redis 使用 压缩列表(ziplist)跳表(skiplist) 来实现有序集合。
  • 结构
    • Ziplist:小型集合时使用压缩列表,减少内存开销。
    • Skiplist:当元素数量或元素大小较多时使用跳表,保证数据按分数排序和高效的范围查询。
    • Hashtable:跳表配合哈希表存储键值对,保证查找效率。
  • 特点
    • 有序性和高效查询:跳表能快速进行范围查询和按分数排序。
    • 节省内存:小集合使用压缩列表存储,减少开销。
  • 适用场景:适合按优先级或分数排序的场景,如排行榜、任务调度等。

5. 哈希(Hash)

  • 实现方式:Redis 使用 压缩列表(ziplist)哈希表(hashtable) 来实现哈希类型。
  • 结构
    • Ziplist:当哈希键包含少量字段时使用压缩列表,节省内存。
    • Hashtable:字段多或较大时使用哈希表,保证高效的读写操作。
  • 特点
    • 高效存储和读取:小型哈希对象用压缩列表减少内存开销。
    • 高效扩展:当哈希结构变大时自动转为哈希表,提升操作速度。
  • 适用场景:适合存储对象数据,如用户信息等,需要存储多个字段的情况。

总结

数据类型实现方式结构描述特点适用场景
字符串简单动态字符串(SDS)- len:记录实际长度
- alloc:已分配空间大小
- buf:存储字符串数据的内容
- 预分配空间减少扩展操作
- 惰性释放优化内存分配
存储单个字符串、整数、浮点数等简单数据
列表双向链表(quicklist)或压缩列表(ziplist)- Quicklist:链表节点存储压缩列表,适合频繁增删
- Ziplist:连续存储短字符串,减少内存占用
- 高效插入、删除操作
- 小数据时内存优化
有序字符串序列,消息或任务队列
集合整数集合(intset)或哈希表(hashtable)- Intset:适合小型整数集合
- Hashtable:适合更多元素或非整数集合,快速插入查找
- 高效查找去重
- 小型集合使用 intset 优化内存
需要快速查重和集合操作的场景,如标签或权限管理
有序集合压缩列表(ziplist)或跳表(skiplist)- Ziplist:小型集合减少内存开销
- Skiplist:支持按分数排序、范围查询
- Hashtable:与跳表结合,确保高效查找
- 支持有序性和快速范围查询
- 小数据时节省内存
排行榜、优先级队列等按分数排序的场景
哈希压缩列表(ziplist)或哈希表(hashtable)- Ziplist:小型哈希节省内存
- Hashtable:字段多时使用,保证读写效率
- 高效读写
- 小型哈希使用 ziplist 优化内存
存储对象数据,如用户信息等需要多个字段的情况

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


http://www.mrgr.cn/news/69060.html

相关文章:

  • 0 -vscode搭建python环境教程参考(windows)
  • HTTP的版本演进,以及他们之间的区别
  • C#自定义特性-SQL
  • el-input 正则表达式校验输入框不能输入汉字
  • 调用 Xinference OpenAI接口时报错 Model not found in the model list, uid
  • python作图设置坐标轴刻度为科学计数法
  • 四期书生大模型实战营(【基础岛】- 第1关 | 书生·浦语大模型开源开放体系)
  • 探针台的维护方法
  • Programming language theory 编程语言理论-03-惰性求值 Lazy Evaluation
  • 代码随想录算法训练营Day13 | 二叉树理论基础、递归遍历、迭代遍历、统一迭代、层序遍历
  • Kafka经典面试题
  • 前端必知必会-JavaScript 数组属性和方法
  • JDBC学习记录
  • 【万方数据】protobuf 逆向
  • jdk 1.8新特性--接口增强
  • Node.js 常用工具util、文件系统使用介绍 (基础介绍 七)
  • C语言多维数组抽象理解:切格子思维
  • Go 中的泛型,日常如何使用
  • D63【python 接口自动化学习】- python基础之数据库
  • 随身 WiFi 锁频段、频点和小区提升网速
  • 24-11-9-读书笔记(三十二)-《契诃夫文集》(六)上([俄] 契诃夫 [译] 汝龙)药品是甜的,真理是美的,咖啡是苦的,生活是什么啊?
  • Linux 零拷贝技术
  • VScode中使用Cmake遇到的问题及其解决方法[最全+亲测有效]
  • 食品加工厂废水处理设备结构与功能
  • 【梯度下降法优化】随机梯度下降、牛顿法、动量法、Nesterov、AdaGrad、RMSprop、Adam
  • Chromium 中chrome.tabs扩展接口定义c++