Redis常见数据类型及应用场景

发布于:2025-09-01 ⋅ 阅读:(17) ⋅ 点赞:(0)

好的,我们来详细讲解 Redis 的数据结构及其应用场景。Redis 的强大之处不仅仅在于它支持简单的键值对,更在于它提供了丰富的数据结构,每种结构都针对特定类型的应用场景进行了优化。

核心数据结构与应用场景

Redis 主要支持以下五种核心数据结构:String(字符串)Hash(哈希)List(列表)Set(集合)Sorted Set(有序集合)。此外,还有 Bitmaps、HyperLogLogs、Streams 等更高级的结构。


1. String(字符串)

这是最简单也是最基础的数据类型。一个 Key 对应一个 Value。Value 不仅是字符串,也可以是数字(整数或浮点数),并且可以对数字进行自增/自减操作。

  • 内部实现:基于简单动态字符串(SDS)实现,可以修改的字符串,预分配内存,减少内存频繁分配。
  • 常用命令SET, GET, MSET, MGET, INCR, DECR, INCRBY

应用场景

  • 缓存:最经典的场景。将数据库查询结果、热点数据、会话信息(Session)等序列化后存入 String,加快访问速度。
    • SET user:1001 "{name: 'Alice', email: 'alice@example.com'}"
  • 计数器:利用 INCRDECR 命令实现点赞数、浏览数、库存计数等。这些操作是原子性的,非常适合高并发场景。
    • INCR article:1001:views
  • 分布式锁:利用 SET key value NX EX seconds 命令(当 key 不存在时设置,并设置过期时间)可以实现简单的分布式锁。
  • Session 共享:在集群服务中,将用户的登录会话信息集中存储在 Redis 中,实现多台服务器共享 Session。

2. Hash(哈希)

类似于 Java 中的 Map<String, Object>,是一组键值对的集合。非常适合存储对象。

  • 内部实现:底层有两种编码方式:ziplist(压缩列表,在元素少、体积小时使用)和 hashtable(哈希表)。
  • 常用命令HSET, HGET, HMSET, HMGET, HGETALL, HINCRBY

应用场景

  • 存储对象:存储用户信息、商品信息等需要多个字段的对象。相比将整个对象序列化成 String,Hash 可以单独获取、修改某个字段,更节省网络带宽和存储空间。
    • HSET user:1001 name "Alice" age "30" email "alice@example.com"
    • HGET user:1001 name -> “Alice”
  • 购物车:以用户ID为 Key,商品ID为 Field,商品数量为 Value。
    • HSET cart:1001 product:5001 3 (用户1001的商品5001数量为3)
    • HINCRBY cart:1001 product:5001 1 (增加1件)

3. List(列表)

一个简单的字符串列表,按插入顺序排序。你可以从列表的头部(左边)或尾部(右边)添加元素。

  • 内部实现:底层是 quicklist(快速列表),它是多个 ziplist 通过双向指针组成的链表,兼顾了空间效率和插入性能。
  • 常用命令LPUSH, RPUSH, LPOP, RPOP, LRANGE, BLPOP (阻塞操作)

应用场景

  • 消息队列:利用 LPUSH + BRPOP 可以实现一个简单的 FIFO(先进先出)队列。生产者从左边推入消息,消费者用阻塞方式从右边取出消息。
  • 最新列表:例如最新文章、最新评论、朋友圈时间线。利用 LPUSH 加入新元素,再用 LRANGE 0 9 获取最新的10条。
    • LPUSH news:latest "News ID 10086"
  • 记录用户操作历史:例如用户的最近搜索、最近浏览记录。

4. Set(集合)

Redis 的 Set 是 String 类型的无序集合,集合内的元素是唯一的,不允许重复。

  • 内部实现:底层是 intset(整数集合,当元素都是整数且数量少时)或 hashtable(哈希表,value 为 null)。
  • 常用命令SADD, SMEMBERS, SISMEMBER, SINTER (交集), SUNION (并集), SDIFF (差集)

应用场景

  • 标签(Tag):给用户、文章等对象打标签。可以很方便地求交集、并集等。
    • SADD article:1001:tags "tech" "redis" "database"
    • SADD user:1002:tags "tech" "python"
    • SINTER article:1001:tags user:1002:tags -> 获取共同标签 “tech”
  • 共同关注/好友:利用 SINTER 可以轻松求出两个用户的共同好友。
  • 抽奖/秒杀:利用 SADD 将所有参与用户ID加入,可以自动保证唯一性,不会重复添加。SMEMBERS 可以列出所有参与者。
  • 黑白名单:将需要过滤的 ID 放入 Set,用 SISMEMBER 快速判断某个 ID 是否在名单内。

5. Sorted Set(有序集合 / ZSet)

与 Set 类似,也是 String 类型元素的集合,且不允许重复。但每个元素都会关联一个 double 类型的分数(score)。Redis 正是通过分数来为集合中的成员进行从小到大的排序。成员是唯一的,但分数可以重复。

  • 内部实现:底层是 ziplist(压缩列表)或 skiplist(跳跃表) + dict(字典)的组合,跳跃表保证范围查询的效率,字典保证按成员查询的效率。
  • 常用命令ZADD, ZRANGE (按分数正序), ZREVRANGE (按分数倒序), ZRANK, ZREVRANK, ZRANGEBYSCORE

应用场景

  • 排行榜:这是最经典的应用场景。将分数设为点击量、销量、热度等,自动进行排序。
    • ZADD leaderboard 100 "player1" 200 "player2"
    • ZREVRANGE leaderboard 0 9 WITHSCORES -> 获取排行榜前十名
  • 带权重的队列:分数可以作为优先级,实现优先级队列。
  • 范围查找:例如处理成绩表,快速查找分数在 [90, 100] 之间的学生。
    • ZRANGEBYSCORE grades 90 100
  • 延时任务:将任务的执行时间作为 score,用一个进程轮询获取到期的任务(ZRANGEBYSCORE key 0 <当前时间戳>)。

其他高级数据结构

  • Bitmaps(位图): 本质上是 String,但可以对字符串的位进行操作。适用于大量布尔值的存储,如用户签到记录(每天1bit)、活跃用户统计,极其节省空间。
  • HyperLogLogs: 用于做基数统计(估算一个集合中不重复元素的个数),标准误差仅0.81%。优点是非常节省空间。适用于统计网站的 UV(独立访客)、搜索关键词的不重复数量等,PFADD, PFCOUNT, PFMERGE
  • Geospatial(地理空间): 可以存储地理坐标,并计算距离、查找范围内成员等。适用于附近的人、地理位置推荐。
  • Streams(流): Redis 5.0 引入,专门为消息队列设计,支持多消费者组、消息持久化、确认机制,功能比 List 更强大,是更专业的消息队列解决方案。

总结与选择建议

数据结构 特性 典型应用场景
String 简单键值,支持数字和位操作 缓存、计数器、分布式锁
Hash 适合存储对象,可部分更新 用户信息、购物车、配置项
List 有序、可重复,支持阻塞操作 消息队列、最新列表、历史记录
Set 无序、唯一,支持集合运算 标签、共同好友、抽奖、黑白名单
Sorted Set 唯一、有序(按分数排序) 排行榜、优先级队列、范围查找
Bitmaps 极省空间的布尔状态存储 用户签到、活跃用户统计
HyperLogLog 极省空间的基数估算 网站UV统计
Streams 持久化的消息流 复杂消息队列

选择时考虑以下几点

  1. 数据形态:是需要一个对象(Hash)、一个列表(List)、一个不重复集合(Set)还是一个带排序的集合(ZSet)?
  2. 操作类型:是需要频繁读取部分字段(Hash),还是需要排序(ZSet),或是需要集合运算(Set)?
  3. 性能与效率:String 存储序列化对象虽然简单,但修改一个字段就需要整个读写,不如 Hash 高效。在元素较少时,Redis 会使用更紧凑的编码(如 ziplist)来节省内存。