Skip to content

Redis数据结构及应用场景详解

一、Redis是什么?

Redis(Remote Dictionary Server)是一个开源的内存键值数据库,支持多种数据结构,提供持久化、事务、发布订阅等功能。与传统数据库不同,Redis将数据存储在内存中,因此读写性能极高(10万+/秒操作),通常用作缓存、消息队列和实时数据处理。


数据结构详解

1. String(字符串)

一、是什么?
最基础的数据类型,可存储文本(最大512MB)、数字或二进制数据。

二、解决什么问题

  • 存储简单键值对
  • 实现原子计数器
  • 缓存简单对象

三、核心命令
SET/GET/INCR/DECR/APPEND

四、应用场景

  • 缓存HTML片段
  • 文章阅读量计数器
  • 分布式锁(SET key value NX EX
  • 存储序列化对象(JSON/protobuf)

五、Java示例

java
// 使用Jedis客户端
Jedis jedis = new Jedis("localhost");
// 设置值
jedis.set("article:100:views", "0");
// 原子增加
jedis.incr("article:100:views");
// 获取值
String views = jedis.get("article:100:views");

六、注意事项

  • 大文本影响内存,需监控大小
  • 数字类型可用INCRBY批量增加

2. Hash(哈希表)

一、是什么?
键值对集合,类似Java的Map<String, String>,适合存储对象。

二、解决什么问题

  • 结构化数据存储
  • 部分字段更新(避免读取整个对象)

三、核心命令
HSET/HGET/HMSET/HGETALL/HDEL

四、应用场景

  • 用户属性存储(姓名/年龄/邮箱)
  • 商品详情页
  • 动态字段配置

五、Java示例

java
// 存储用户信息
Map<String, String> user = new HashMap<>();
user.put("name", "Alice");
user.put("age", "28");
jedis.hset("user:1001", user);

// 获取单个字段
String name = jedis.hget("user:1001", "name");

六、注意事项

  • 字段过多影响性能,建议控制在1000以内
  • 不支持嵌套数据结构

3. List(列表)

一、是什么?
双向链表结构,按插入顺序排序,支持头尾操作。

二、解决什么问题

  • 有序数据集合
  • 队列/栈实现

三、核心命令
LPUSH/RPUSH/LPOP/RPOP/LRANGE

四、应用场景

  • 消息队列(生产者-消费者)
  • 最新文章列表(保留100条)
  • 操作日志记录

五、Java示例

java
// 消息队列生产者
jedis.lpush("msg_queue", "task1");

// 消费者
String task = jedis.rpop("msg_queue");

// 获取最新10条日志
List<String> logs = jedis.lrange("app_logs", 0, 9);

六、注意事项

  • 长列表遍历性能低,避免LRANGE 0 -1
  • 阻塞命令BLPOP可避免轮询

4. Set(集合)

一、是什么?
无序的唯一值集合,支持交/并/差集运算。

二、解决什么问题

  • 去重存储
  • 关系运算(共同好友)

三、核心命令
SADD/SMEMBERS/SINTER/SUNION

四、应用场景

  • 用户标签系统
  • 抽奖去重
  • 共同关注(交集计算)

五、Java示例

java
// 添加标签
jedis.sadd("user:1001:tags", "sports", "music");

// 获取共同兴趣
jedis.sinter("user:1001:tags", "user:1002:tags");

// 随机抽奖
String winner = jedis.srandmember("lottery_pool");

六、注意事项

  • SMEMBERS全量返回可能阻塞,用SSCAN分批获取
  • 大集合运算消耗CPU

5. Sorted Set(有序集合)

一、是什么?
带分数的Set,元素按分数排序(分数可重复)。

二、解决什么问题

  • 带权重的排行榜
  • 范围查询(如时间范围)

三、核心命令
ZADD/ZRANGE/ZREVRANK/ZRANGEBYSCORE

四、应用场景

  • 游戏积分排行榜
  • 延迟队列(分数=执行时间戳)
  • 热点新闻TOP10

五、Java示例

java
// 添加玩家积分
jedis.zadd("game_leaderboard", 3500, "player1");

// 获取TOP3
Set<String> topPlayers = jedis.zrevrange("game_leaderboard", 0, 2);

// 查询黄金段位玩家(3000-4000分)
Set<String> goldPlayers = jedis.zrangeByScore("game_leaderboard", 3000, 4000);

六、注意事项

  • 分数用double存储,避免精度问题
  • ZRANGE复杂度O(log(N)),性能优异

Redis数据结构及应用场景详解(Redisson实现)

1. String(字符串)

Java示例(Redisson)

java
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class StringExample {
    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create(config);
        
        // 设置键值
        RBucket<String> bucket = redisson.getBucket("user:1001:name");
        bucket.set("Alice");
        
        // 原子计数器
        RAtomicLong counter = redisson.getAtomicLong("article:200:views");
        counter.set(100);
        counter.incrementAndGet(); // 原子增加
        
        // 获取值
        System.out.println("User name: " + bucket.get());
        System.out.println("View count: " + counter.get());
        
        redisson.shutdown();
    }
}

2. Hash(哈希表)

Java示例(Redisson)

java
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;

public class HashExample {
    public static void main(String[] args) {
        // 初始化同上
        RedissonClient redisson = ...;
        
        // 存储用户对象
        RMap<String, String> userMap = redisson.getMap("user:1001");
        userMap.put("name", "Alice");
        userMap.put("email", "alice@example.com");
        userMap.put("age", "30");
        
        // 部分更新
        userMap.fastPut("email", "new_email@example.com");
        
        // 获取所有字段
        userMap.entrySet().forEach(entry -> 
            System.out.println(entry.getKey() + ": " + entry.getValue())
        );
        
        redisson.shutdown();
    }
}

3. List(列表)

Java示例(Redisson)

java
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;

public class ListExample {
    public static void main(String[] args) {
        // 初始化同上
        RedissonClient redisson = ...;
        
        // 消息队列生产者
        RList<String> msgQueue = redisson.getList("message_queue");
        msgQueue.add("Task1: Process invoices");
        msgQueue.add("Task2: Generate reports");
        
        // 消费者
        if (!msgQueue.isEmpty()) {
            String task = msgQueue.remove(0);
            System.out.println("Processing: " + task);
        }
        
        // 获取最新5条日志
        RList<String> logs = redisson.getList("app_logs");
        logs.add("2023-10-01: System started");
        logs.add("2023-10-01: User logged in");
        
        logs.range(0, 4).forEach(System.out::println);
        
        redisson.shutdown();
    }
}

4. Set(集合)

Java示例(Redisson)

java
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;

public class SetExample {
    public static void main(String[] args) {
        // 初始化同上
        RedissonClient redisson = ...;
        
        // 用户标签
        RSet<String> userTags = redisson.getSet("user:1001:tags");
        userTags.add("sports");
        userTags.add("technology");
        userTags.add("sports"); // 自动去重
        
        // 共同兴趣计算
        RSet<String> user2Tags = redisson.getSet("user:1002:tags");
        user2Tags.add("technology");
        user2Tags.add("music");
        
        RSet<String> commonTags = userTags.intersection(user2Tags);
        System.out.println("Common tags: " + commonTags);
        
        redisson.shutdown();
    }
}

5. Sorted Set(有序集合)

Java示例(Redisson)

java
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RedissonClient;

public class SortedSetExample {
    public static void main(String[] args) {
        // 初始化同上
        RedissonClient redisson = ...;
        
        // 游戏排行榜
        RScoredSortedSet<String> leaderboard = redisson.getScoredSortedSet("game_leaderboard");
        leaderboard.add(4200.0, "Player1");
        leaderboard.add(3850.5, "Player2");
        leaderboard.add(4010.0, "Player3");
        
        // 获取TOP3玩家
        System.out.println("Top players:");
        leaderboard.entryRangeReversed(0, 2).forEach(entry -> 
            System.out.println(entry.getScore() + ": " + entry.getValue())
        );
        
        // 范围查询(黄金段位 3500-4000分)
        System.out.println("Gold players:");
        leaderboard.entryRange(3500, true, 4000, true).forEach(entry ->
            System.out.println(entry.getValue() + " - " + entry.getScore())
        );
        
        redisson.shutdown();
    }
}

Redisson高级特性

1. 分布式锁
java
RLock lock = redisson.getLock("order:lock");
try {
    if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
        // 处理业务逻辑
        processOrder();
    }
} finally {
    lock.unlock();
}
2. 布隆过滤器
java
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("user_filter");
bloomFilter.tryInit(100000L, 0.03);  // 10万数据,3%误判率

bloomFilter.add("user1001@example.com");
boolean exists = bloomFilter.contains("user1002@example.com");
3. 分布式队列
java
RBlockingQueue<String> queue = redisson.getBlockingQueue("task_queue");
// 生产者
queue.offer("task_data");

// 消费者(阻塞等待)
String task = queue.take();

最佳实践总结

  1. 连接管理

    java
    Config config = new Config();
    config.useSingleServer()
          .setAddress("redis://127.0.0.1:6379")
          .setConnectionPoolSize(64);  // 优化连接池
  2. 数据序列化

    java
    config.setCodec(new JsonJacksonCodec());  // 使用JSON序列化
  3. 超时控制

    java
    RBucket<String> bucket = redisson.getBucket("key");
    bucket.set("value", 30, TimeUnit.MINUTES);  // 设置TTL
  4. 批量操作

    java
    RMap<String, String> map = redisson.getMap("user:1001");
    Map<String, String> newData = Map.of("city", "NY", "job", "Engineer");
    map.putAll(newData);  // 批量更新
  5. 异步处理

    java
    RFuture<Void> future = bucket.setAsync("async_value");
    future.whenComplete((res, ex) -> {
        if (ex == null) System.out.println("Async set complete");
    });

Redisson优势

  1. 分布式对象抽象(Map/List/Set等实现java.util接口)
  2. 支持异步/反应式编程
  3. 内置分布式锁、限流器等工具
  4. 自动连接管理和故障转移
  5. 与Spring框架无缝集成

通过Redisson,开发者可以用面向对象的方式操作Redis,显著降低分布式系统开发复杂度。

数据结构对比

类型特点适用场景是否有序
String简单键值缓存/计数器
Hash字段映射对象存储
List双向链表消息队列/时间线插入顺序
Set唯一元素标签/去重
SortedSet带分数排序排行榜/范围查询分数排序

总结

  1. String:简单缓存和计数器首选
  2. Hash:存储结构化对象(用户/商品)
  3. List:消息队列和时间线场景
  4. Set:去重和集合运算(共同好友)
  5. SortedSet:排行榜和范围查询(如积分榜)

最佳实践

  • 缓存场景优先用String(简单)或Hash(结构化)
  • 实时排行榜必用SortedSet
  • 消息队列用List或Streams(Redis5.0+)
  • 集合运算用Set,注意数据规模
  • 所有数据结构都支持TTL过期,善用EXPIRE