Redisson 提供的分布式 Set(RSet)和 List(RList)是基于 Redis 实现的分布式集合,支持与 Java 标准集合类似的操作,但具备跨节点共享、原子性操作和丰富的扩展特性。以下是它们的核心应用场景及典型用法:
一、分布式 Set(RSet)的应用场景
1. 数据去重
- 场景:在分布式系统中收集唯一元素(如用户 ID、设备 ID),避免重复处理。
- 示例:统计网站 UV(独立访客)
RSet<String> uniqueVisitors = redisson.getSet("website:uv"); // 用户访问时记录(自动去重) uniqueVisitors.add(userId); // 获取总 UV long uvCount = uniqueVisitors.size();
2. 关系判断
- 场景:判断元素是否存在(如用户是否点赞、是否收藏)。
- 示例:用户点赞功能
RSet<String> likes = redisson.getSet("post:1001:likes"); // 用户点赞 likes.add(userId); // 检查用户是否已点赞 boolean hasLiked = likes.contains(userId);
3. 集合运算
- 场景:求交集、并集、差集(如用户标签匹配、共同好友)。
- 示例:共同好友推荐
RSet<String> user1Friends = redisson.getSet("user:1:friends"); RSet<String> user2Friends = redisson.getSet("user:2:friends"); // 求共同好友(交集) RSet<String> commonFriends = user1Friends.readIntersection(user2Friends);
4. 分布式锁资源池
- 场景:管理有限资源的使用状态(如数据库连接池、线程池)。
- 示例:资源分配
RSet<String> availableResources = redisson.getSet("resource:pool"); // 初始化资源 availableResources.addAll(Arrays.asList("resource1", "resource2", "resource3")); // 获取资源(原子性操作) String resource = null; Iterator<String> iterator = availableResources.iterator(); if (iterator.hasNext()) { resource = iterator.next(); availableResources.remove(resource); }
二、分布式 List(RList)的应用场景
1. 消息队列(FIFO)
- 场景:实现异步任务队列、消息广播(需结合发布订阅)。
- 示例:订单处理队列
RList<String> orderQueue = redisson.getList("order:queue"); // 生产者:添加订单到队列 orderQueue.add(orderId); // 消费者:从队列取订单(按 FIFO 顺序) String orderId = orderQueue.pollFirst();
2. 历史记录/操作日志
- 场景:记录用户操作历史、系统审计日志(按时间顺序)。
- 示例:用户操作记录
RList<String> userOperations = redisson.getList("user:" + userId + ":operations"); // 添加操作记录(最新操作在队首) userOperations.addFirst("login at " + LocalDateTime.now()); // 获取最近10条记录 List<String> recentOperations = userOperations.range(0, 9);
3. 排行榜(Top-N)
- 场景:实时更新并展示热门数据(如热搜榜、销量排行)。
- 示例:商品销量排行(简化版)
RList<Product> salesRanking = redisson.getList("sales:ranking"); // 定期更新排行榜(如每小时重新排序) List<Product> topProducts = queryTopProductsFromDB(); salesRanking.clear(); salesRanking.addAll(topProducts); // 获取前三名 List<Product> top3 = salesRanking.range(0, 2);
4. 分布式任务分片
- 场景:将大任务分割为多个子任务,分发给不同节点处理。
- 示例:数据批量处理
RList<String> taskList = redisson.getList("data:processing:tasks"); // 主节点:拆分任务 List<String> dataChunks = splitLargeData(); taskList.addAll(dataChunks); // 工作节点:领取任务 String task = taskList.removeFirst(); processTask(task);
三、Set 与 List 的对比选择
| 特性 | 分布式 Set(RSet) | 分布式 List(RList) |
|---|---|---|
| 元素唯一性 | ✅(自动去重) | ❌(允许重复) |
| 顺序性 | ❌(无序) | ✅(插入顺序) |
| 查询效率 | O(1)(基于哈希) | O(n)(需遍历) |
| 典型操作 | 添加、包含判断、集合运算 | 首尾插入/删除、范围查询 |
| 应用场景 | 去重、关系判断、资源池管理 | 队列、日志记录、排行榜 |
四、Redisson 集合的高级特性
-
原子性操作:
// Set 的原子性添加(返回是否新增成功) boolean added = rSet.addIfAbsent("element"); // List 的原子性操作 rList.addAndGet(0, "element"); // 在指定位置添加元素 -
本地缓存:
// 配置本地缓存,减少网络调用 RLocalCachedSet<String> cachedSet = redisson.getLocalCachedSet( "cachedSet", LocalCachedSetOptions.defaults() ); -
异步操作:
// 异步添加元素到 Set RFuture<Boolean> future = rSet.addAsync("element"); future.thenAccept(result -> System.out.println("添加结果: " + result)); -
事件监听:
// 监听 List 元素变化 rList.addListener(new ListAddListener<String>() { @Override public void onListAdd(String element) { System.out.println("新增元素: " + element); } });
五、注意事项
-
性能考虑:
- List 的随机访问和中间插入性能较差(O(n)),适合头尾操作;
- Set 的集合运算(如交集)在元素量大时可能影响性能。
-
内存占用:
- Redis 是内存数据库,大量数据需谨慎使用,可结合过期策略(如
RListCache)。
- Redis 是内存数据库,大量数据需谨慎使用,可结合过期策略(如
-
序列化:
- 存储复杂对象时需确保正确实现序列化(如实现
Serializable接口)。
- 存储复杂对象时需确保正确实现序列化(如实现
总结
Redisson 的分布式 Set 和 List 通过 Redis 实现了跨节点的数据共享,结合原子性操作、本地缓存和事件监听等特性,适用于数据去重、消息队列、排行榜等多种场景。选择时需根据业务需求权衡元素唯一性、顺序性和查询效率。