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 >

类型对比

数据类型 引入版本 特点 使用场景
BitMap 2.2 位操作,高效标记和统计 用户签到、活跃用户统计
HyperLogLog 2.8 基数估计,固定存储 UV统计、大数据去重计数
GEO 3.2 地理位置存储和查询 附近的人、POI查询
Stream 5.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 的这种"结构适应性"设计,让它可以根据数据特点自动调整底层实现,在保证数据存储灵活性的同时,保持高效的查询和操作速度。

相关推荐
努力的小雨3 分钟前
快速上手 KSQL:轻松与数据库交互的利器
数据库·经验分享
Gentle5866 分钟前
labview中连接sql server数据库查询语句
数据库·labview
Gentle5867 分钟前
labview用sql server数据库存取数据到一个单元格
数据库·labview
2401_8576363910 分钟前
共享汽车管理新纪元:SpringBoot框架应用
数据库·spring boot·汽车
菲兹园长10 分钟前
表的设计(MYSQL)
数据库·mysql
Java Fans25 分钟前
MySQL数据库常用命令大全(完整版——表格形式)
数据库·mysql
起飞的风筝38 分钟前
【redis】—— 环境搭建教程
数据库·redis·缓存
白萝卜弟弟41 分钟前
【MySQL】MySQL函数之JSON_EXTRACT
数据库·mysql·json
gjh120843 分钟前
MySQL常见面试题
数据库·mysql
韭菜盖饭1 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode