Redis五大数据结构:从场景到实现

一、引子:为什么Redis需要五大数据结构? 很多人的疑问:Memcached只有String一种数据结构,Redis为什么需要五种? 核心答案:不同的业务场景需要不同的数据结构。 1.1 如果只有String会怎样? 假设我们要实现一个排行榜功能,只有String的话: // ❌ 方案1:用String存储整个排行榜(JSON序列化) // 问题:每次更新一个用户分数,需要序列化/反序列化整个排行榜 public void updateScore(Long userId, int score) { // 1. 读取整个排行榜(反序列化) String json = redisTemplate.opsForValue().get("rank:list"); List<User> rankList = JSON.parseArray(json, User.class); // 10000个用户 // 2. 更新一个用户的分数 for (User user : rankList) { if (user.getId().equals(userId)) { user.setScore(score); break; } } // 3. 重新排序 rankList.sort((a, b) -> b.getScore() - a.getScore()); // 4. 写入Redis(序列化) String newJson = JSON.toJSONString(rankList); redisTemplate.opsForValue().set("rank:list", newJson); } // 性能问题: // - 读取:反序列化10000个用户,耗时100ms // - 排序:O(NlogN) = 10000*log(10000) ≈ 130000次比较 // - 写入:序列化10000个用户,耗时100ms // 总耗时:200ms+(单次更新) // ✅ 方案2:使用Redis ZSet(有序集合) // 优势:Redis内部维护排序,O(logN)复杂度 public void updateScore(Long userId, int score) { redisTemplate.opsForZSet().add("rank:zset", userId.toString(), score); } // 性能提升: // - 写入:O(logN) = log(10000) ≈ 13次比较 // - 总耗时:1ms // 性能提升:200倍 核心洞察: ...

2025-11-03 · maneng

Redis五大数据结构:从场景到实现

一、引子:为什么Redis需要五大数据结构? 很多人的疑问:Memcached只有String一种数据结构,Redis为什么需要五种? 核心答案:不同的业务场景需要不同的数据结构。 1.1 如果只有String会怎样? 假设我们要实现一个排行榜功能,只有String的话: // ❌ 方案1:用String存储整个排行榜(JSON序列化) // 问题:每次更新一个用户分数,需要序列化/反序列化整个排行榜 public void updateScore(Long userId, int score) { // 1. 读取整个排行榜(反序列化) String json = redisTemplate.opsForValue().get("rank:list"); List<User> rankList = JSON.parseArray(json, User.class); // 10000个用户 // 2. 更新一个用户的分数 for (User user : rankList) { if (user.getId().equals(userId)) { user.setScore(score); break; } } // 3. 重新排序 rankList.sort((a, b) -> b.getScore() - a.getScore()); // 4. 写入Redis(序列化) String newJson = JSON.toJSONString(rankList); redisTemplate.opsForValue().set("rank:list", newJson); } // 性能问题: // - 读取:反序列化10000个用户,耗时100ms // - 排序:O(NlogN) = 10000*log(10000) ≈ 130000次比较 // - 写入:序列化10000个用户,耗时100ms // 总耗时:200ms+(单次更新) // ✅ 方案2:使用Redis ZSet(有序集合) // 优势:Redis内部维护排序,O(logN)复杂度 public void updateScore(Long userId, int score) { redisTemplate.opsForZSet().add("rank:zset", userId.toString(), score); } // 性能提升: // - 写入:O(logN) = log(10000) ≈ 13次比较 // - 总耗时:1ms // 性能提升:200倍 核心洞察: ...

2025-11-03 · maneng

String类型深度解析:最简单也最强大

引言 在Redis的五大基础数据类型中,String是最基础、最常用的一种。据统计,在实际生产环境中,80%以上的Redis键都是String类型。 但String远不止"字符串"这么简单。它可以: 存储任意二进制数据(文本、数字、图片、序列化对象) 作为计数器(原子性递增/递减) 实现分布式锁 存储位图数据 今天我们从第一性原理出发,理解String的本质和强大之处。 一、String的本质 1.1 不只是字符串 在Redis中,String类型的"String"是一个容易误导人的名字。它实际上是: 二进制安全的字节数组(Binary Safe Byte Array) 这意味着: ✅ 可以存储文本:“hello world” ✅ 可以存储数字:123456 ✅ 可以存储JSON:{"name":"Redis"} ✅ 可以存储序列化对象:Java对象、Protobuf ✅ 可以存储二进制数据:图片、音频(理论上,但不推荐) 1.2 底层实现:SDS Redis使用自己实现的简单动态字符串(Simple Dynamic String, SDS),而不是C语言原生的字符串。 C字符串的问题: char* str = "hello"; // 问题1:获取长度需要遍历,O(n) int len = strlen(str); // 问题2:不是二进制安全,遇到\0就截断 char* binary = "hello\0world"; // 只能读到"hello" // 问题3:缓冲区溢出风险 strcat(str, " world"); // 可能溢出 SDS的优势: struct sdshdr { int len; // 已使用长度 int free; // 剩余可用空间 char buf[]; // 实际存储的字节数组 }; 优势: O(1)时间获取长度:直接读取len字段 二进制安全:不依赖\0判断结束 预分配空间:减少内存分配次数 惰性释放:空间不立即释放,可重用 1.3 内存占用 一个简单的String在Redis中的内存占用: ...

2025-01-21 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...