Redis数据结构:别小看这5把“瑞士军刀”,用好了性能飙升!

简介: Redis提供5种基础数据结构及多种高级结构,如String、Hash、List、Set、ZSet,底层通过SDS、跳表等实现高效操作。灵活运用可解决缓存、计数、消息队列、排行榜等问题,结合Bitmap、HyperLogLog、GEO更可应对签到、UV统计、地理位置等场景,是高性能应用的核心利器。

引言:

上一篇文章介绍了Redis的基本概念,了解了Redis 为什么快以及为什么使用单线程操作数据。Redis 受欢迎的另一个原因就是提供了丰富的数据结构,就像一套精密的‘瑞士军刀’,便于我们去解决各种各样的问题。灵活使用redis的数据结构,能让我们高效、优雅地解决业务问题。 今天,就带你深入Redis的“武器库”,看看这5把核心“军刀”如何助你披荆斩棘!

Redis 提供了 5 种基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。

其底层实现主要依赖这 8 种数据结构:简单动态字符串(SDS)、LinkedList(双向链表)、Dict(哈希表/字典)、SkipList(跳表)、Intset(整数集合)、ZipList(压缩列表)、QuickList(快速列表)。

我们要分清这两者的区别:

  • 数据类型是编程方面的概念:是直接提供给开发者使用的
  • 数据结构是底层实现的机制:是计算机层面存储数据的实现方式

    基础数据结构

    1. String (字符串):不只是“Hello World”

  • 本质: 最基础的类型,可存文本、数字(整数/浮点数)、甚至二进制数据(如图片片段)。最多可以容纳的数据长度是 512M
  • 底层: 简单动态字符串 (SDS),比C原生字符串更安全高效,支持动态扩容和预分配。
  • Redis原生命令:
    SET key value [EX seconds]  # 设置键值,可设置过期时间
    GET key                    # 获取值
    INCR key                   # 原子递增
    DECR key                   # 原子递减
    APPEND key value           # 追加内容
    
  • 适用场景: 简单缓存、计数器、分布式锁、小对象存储。

实战案例

  • 原生命令

      # 实现文章阅读量统计
      SET article:1001:views 0
      INCR article:1001:views
    
      # 实现分布式锁
      SETNX lock:order:1001 "1" EX 30
    
  • Java代码片段 :
    // 计数器
    Long views = jedis.incr("article:1001:views");
    // 分布式锁 (简化版)
    String result = jedis.set("lock:order:1001", "client1", "NX", "PX", 30000);
    if ("OK".equals(result)) {
         
        // 获取锁成功,执行业务
    }
    

2. Hash (哈希表):存储“对象”的利器

  • 本质: 键值对集合,特别适合存储对象(如用户信息、商品属性)。
  • 底层: 压缩列表 (ziplist - 小数据时) 或 哈希表 (hashtable - 大数据时)。
  • 优点:
    • 结构化存储: 一个Key对应多个field-value,天然表示对象。
    • 高效操作: HGET/HSET 操作单个字段,无需序列化/反序列化整个对象!HGETALL 获取全部。
    • 节省网络: 更新用户姓名?只需HSET user:1001 name "新名字",不用传整个用户对象。
  • 常用命令

    HSET key field value  # 设置字段值
    HGET key field        # 获取字段值
    HGETALL key           # 获取所有字段值
    HINCRBY key field increment  # 字段值递增
    
  • 适用场景: 对象缓存(用户、商品、配置)、需要频繁修改部分字段的场景。

实战案例

  • 原生命令

      # 存储用户信息
      HSET user:1001 name "张三" age 28 email "zhangsan@example.com"
    
      # 更新用户年龄
      HINCRBY user:1001 age 1
    
  • Java代码片段:

    // 存储用户信息
    Map<String, String> userMap = new HashMap<>();
    userMap.put("name", "张三");
    userMap.put("age", "28");
    userMap.put("email", "zhangsan@example.com");
    jedis.hset("user:1001", userMap);
    // 只获取年龄
    String age = jedis.hget("user:1001", "age");
    // 只更新年龄
    jedis.hset("user:1001", "age", "1");
    

    3. List (列表):灵活的双端队列

  • 本质: 有序、可重复元素的集合,按插入顺序排序。双向链表实现。

  • 底层: 压缩列表 (ziplist) 或 双向链表 (linkedlist)。
  • 特点:
    • 队列: LPUSH (左入) + RPOP (右出) = 先进先出 (FIFO) (消息队列、任务队列)
    • 栈: LPUSH (左入) + LPOP (左出) = 后进先出 (LIFO)
    • 最新列表: LPUSH + LTRIM 0 99 = 保持最新的100条数据(最新消息、最新订单)
    • 阻塞操作: BRPOP/BLPOP (没有元素时阻塞等待,实现简单消息队列)
  • 常用命令
    LPUSH key value      # 左侧插入
    RPUSH key value      # 右侧插入
    LPOP key             # 左侧弹出
    RPOP key             # 右侧弹出
    BLPOP key timeout    # 阻塞式左侧弹出
    
  • 适用场景: 消息队列、最新列表(朋友圈、微博)、任务队列、记录操作日志。

实战案例

  • 原生命令

      # 实现消息队列
      LPUSH message:queue "task1"
      RPOP message:queue
    
      # 实现最新文章列表
      LPUSH news:latest "article:1001"
      LTRIM news:latest 0 9  # 只保留最新10条
    
  • Java代码片段:
    // 1. 消息队列 
    jedis.lpush("message:queue", "task1", "task2", "task3"); 
    String task = jedis.rpop("message:queue");
    // 消费者 (阻塞式)
    List<String> task = jedis.brpop(30, "message:queue"); // 阻塞30秒等待
    if (task != null) {
         
        String taskData = task.get(1); // 实际数据在返回列表的第二个元素
        // 处理任务...
    }
    // 2. 最新文章列表 
    jedis.lpush("news:latest", "article:1001", "article:1002", "article:1003"); 
    jedis.ltrim("news:latest", 0, 9); // 只保留最新10条
    

4. Set (集合):排重与社交的基石

  • 本质: 无序、唯一元素的集合。自动去重!
  • 底层: 整数集合 (intset - 纯整数小集合) 或 哈希表 (hashtable)。
  • 超能力:

    • 去重: SADD 自动过滤重复元素。
    • 集合运算: SINTER (交集-共同好友) SUNION (并集) SDIFF (差集-可能认识的人)。
    • 随机元素: SRANDMEMBER (抽奖) SPOP (随机移除并返回 - 秒杀资格)。
    • 成员存在性: SISMEMBER (快速判断用户是否在某个组/拥有标签)。
  • 常用命令:

    SADD key member      # 添加元素
    SREM key member      # 移除元素
    SISMEMBER key member # 判断元素是否存在
    SINTER key1 key2     # 求交集
    
  • 适用场景: 标签系统、社交关系(好友、关注)、唯一性检查(抽奖用户)、黑白名单、随机推荐。

实战案例

  • 原生命令

      # 文章标签系统
      SADD article:1001:tags "Redis" "数据库" "缓存"
    
      # 共同好友
      SINTER user:1001:friends user:1002:friends
    
  • Java代码片段 (共同好友):
    // 1. 标签系统 
    jedis.sadd("article:1001:tags", "Redis", "数据库", "缓存"); 
    // 2. 检查标签 
    boolean isMember = jedis.sismember("article:1001:tags", "Redis"); System.out.println("是否包含Redis标签:" + isMember); 
    // 输出:true 
    // 3. 共同好友 
    jedis.sadd("user:1001:friends", "user1002", "user1003", "user1004"); jedis.sadd("user:1002:friends", "user1001", "user1003", "user1005"); Set<String> commonFriends = jedis.sinter("user:1001:friends", "user:1002:friends"); 
    System.out.println("共同好友:" + commonFriends); 
    // 输出:[user1003]
    

5. Sorted Set (ZSet - 有序集合):排行榜的王者

  • 本质: Set的升级版!元素唯一,但每个元素关联一个score (分数)。元素按score排序(从小到大)。分数可相同,相同分数按字典序排。
  • 底层: 压缩列表 + 跳表 (skiplist)。跳表是实现高效范围查询的关键。
  • 特点:
    • 元素唯一
    • 按分数排序
    • 支持范围查询
  • 常用命令
    ZADD key score member  # 添加元素
    ZRANGE key start stop [WITHSCORES]  # 获取范围
    ZREVRANK key member    # 获取逆序排名
    ZSCORE key member      # 获取分数
    
  • 适用场景:排行榜、延迟队列、带权重的元素存储

实战案例

  • 原生命令

      # 游戏排行榜
      ZADD game:leaderboard 5000 "player1" 4500 "player2"
    
      # 获取TOP3
      ZREVRANGE game:leaderboard 0 2 WITHSCORES
    
  • Java代码片段:
    // 1. 排行榜 
    jedis.zadd("game:leaderboard", 5000, "player1"); jedis.zadd("game:leaderboard", 4500, "player2"); jedis.zadd("game:leaderboard", 4800, "player3"); 
    // 2. 获取TOP3 
    Set<String> topPlayers = jedis.zrevrange("game:leaderboard", 0, 2); System.out.println("TOP3玩家:" + topPlayers); 
    // 输出:[player1, player3, player2] 
    // 3. 获取玩家排名 
    Long rank = jedis.zrevrank("game:leaderboard", "player2"); System.out.println("player2排名:" + (rank + 1)); 
    // 输出:3 
    // 4. 范围查询 
    Set<String> players = jedis.zrangeByScore("game:leaderboard", 4700, 5100); 
    System.out.println("4700-5100分玩家:" + players); 
    // 输出:[player3, player1]
    

高级数据结构应用

1. 位图(Bitmap)——极省空间的统计工具

特点

  • 基于String实现
  • 极省空间
  • 支持位运算

应用场景:用户签到、活跃用户统计、特征标记

实战案例

# 用户签到
SETBIT sign:202405:user1 15 1 # 5月15日签到
# 统计当月签到天数
BITCOUNT sign:202405:user1

2. HyperLogLog——海量数据去重统计

特点

  • 固定12KB内存
  • 误差率0.81%
  • 支持合并

应用场景:UV统计、大规模去重计数

实战案例

# 统计UV
PFADD uv:20240501 "user1" "user2" "user3"
PFCOUNT uv:20240501

3. 地理空间索引(GEO)——位置服务好帮手

特点

  • 基于Sorted Set实现
  • 支持距离计算
  • 支持范围查询

应用场景:附近的人、位置搜索、地理围栏

实战案例

# 添加地理位置
GEOADD locations 116.404 39.915 "天安门" 121.474 31.230 "上海外滩"
# 查询5公里内的地点
GEORADIUS locations 116.404 39.915 5 km

数据结构选型指南

需求场景 推荐数据结构 原因
简单键值存储 String 简单高效
对象存储 Hash 字段独立操作
消息队列 List 顺序访问
去重集合 Set 自动去重
排行榜 Sorted Set 自动排序
二值统计 Bitmap 极省空间
海量去重统计 HyperLogLog 固定内存消耗
地理位置服务 GEO 内置距离计算

性能优化建议

  1. 避免大Key:单个String不超过10KB,Hash字段不超过1000个
  2. 合理使用管道:减少网络往返时间
  3. 设置合适过期时间:避免内存浪费
  4. 使用SCAN替代KEYS:避免阻塞
  5. 考虑数据分片:超大集合可考虑分片存储

结语:Redis数据结构的力量

Redis通过精心设计的数据结构,在性能、功能和易用性之间取得了完美平衡。掌握这些数据结构,你就能:

  • 构建高性能缓存系统
  • 实现复杂的业务逻辑
  • 处理海量数据统计
  • 开发实时应用

记住:没有最好的数据结构,只有最适合的数据结构。根据你的具体业务场景,选择最合适的Redis数据结构,才能发挥Redis的最大威力。

相关文章
|
3月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
250 6
|
2月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
273 86
|
4月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
2月前
|
存储 缓存 NoSQL
Redis基础命令与数据结构概览
Redis是一个功能强大的键值存储系统,提供了丰富的数据结构以及相应的操作命令来满足现代应用程序对于高速读写和灵活数据处理的需求。通过掌握这些基础命令,开发者能够高效地对Redis进行操作,实现数据存储和管理的高性能方案。
114 12
|
2月前
|
存储 消息中间件 NoSQL
【Redis】常用数据结构之List篇:从常用命令到典型使用场景
本文将系统探讨 Redis List 的核心特性、完整命令体系、底层存储实现以及典型实践场景,为读者构建从理论到应用的完整认知框架,助力开发者在实际业务中高效运用这一数据结构解决问题。
|
2月前
|
存储 缓存 NoSQL
【Redis】 常用数据结构之String篇:从SET/GET到INCR的超全教程
无论是需要快速缓存用户信息,还是实现高并发场景下的精准计数,深入理解String的特性与最佳实践,都是提升Redis使用效率的关键。接下来,让我们从基础命令开始,逐步揭开String数据结构的神秘面纱。
|
6月前
|
存储 NoSQL 算法
Redis设计与实现——数据结构与对象
Redis 是一个高性能的键值存储系统,其数据结构设计精妙且高效。主要包括以下几种核心数据结构:SDS、链表、字典、跳跃表、整数集合、压缩列表。此外,Redis 对象通过类型和编码方式动态转换,优化内存使用,并支持引用计数、共享对象和淘汰策略(如 LRU/LFU)。这些特性共同确保 Redis 在性能与灵活性之间的平衡。
|
9月前
|
NoSQL 算法 安全
Redis原理—1.Redis数据结构
本文介绍了Redis 的主要数据结构及应用。
Redis原理—1.Redis数据结构
|
6月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?

热门文章

最新文章