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示例
// 使用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示例
// 存储用户信息
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示例
// 消息队列生产者
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示例
// 添加标签
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示例
// 添加玩家积分
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)
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)
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)
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)
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)
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. 分布式锁
RLock lock = redisson.getLock("order:lock");
try {
if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
// 处理业务逻辑
processOrder();
}
} finally {
lock.unlock();
}
2. 布隆过滤器
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. 分布式队列
RBlockingQueue<String> queue = redisson.getBlockingQueue("task_queue");
// 生产者
queue.offer("task_data");
// 消费者(阻塞等待)
String task = queue.take();
最佳实践总结
连接管理:
javaConfig config = new Config(); config.useSingleServer() .setAddress("redis://127.0.0.1:6379") .setConnectionPoolSize(64); // 优化连接池
数据序列化:
javaconfig.setCodec(new JsonJacksonCodec()); // 使用JSON序列化
超时控制:
javaRBucket<String> bucket = redisson.getBucket("key"); bucket.set("value", 30, TimeUnit.MINUTES); // 设置TTL
批量操作:
javaRMap<String, String> map = redisson.getMap("user:1001"); Map<String, String> newData = Map.of("city", "NY", "job", "Engineer"); map.putAll(newData); // 批量更新
异步处理:
javaRFuture<Void> future = bucket.setAsync("async_value"); future.whenComplete((res, ex) -> { if (ex == null) System.out.println("Async set complete"); });
Redisson优势:
- 分布式对象抽象(Map/List/Set等实现java.util接口)
- 支持异步/反应式编程
- 内置分布式锁、限流器等工具
- 自动连接管理和故障转移
- 与Spring框架无缝集成
通过Redisson,开发者可以用面向对象的方式操作Redis,显著降低分布式系统开发复杂度。
数据结构对比
类型 | 特点 | 适用场景 | 是否有序 |
---|---|---|---|
String | 简单键值 | 缓存/计数器 | 无 |
Hash | 字段映射 | 对象存储 | 无 |
List | 双向链表 | 消息队列/时间线 | 插入顺序 |
Set | 唯一元素 | 标签/去重 | 无 |
SortedSet | 带分数排序 | 排行榜/范围查询 | 分数排序 |
总结
- String:简单缓存和计数器首选
- Hash:存储结构化对象(用户/商品)
- List:消息队列和时间线场景
- Set:去重和集合运算(共同好友)
- SortedSet:排行榜和范围查询(如积分榜)
最佳实践:
- 缓存场景优先用String(简单)或Hash(结构化)
- 实时排行榜必用SortedSet
- 消息队列用List或Streams(Redis5.0+)
- 集合运算用Set,注意数据规模
- 所有数据结构都支持TTL过期,善用
EXPIRE