Redisson分布式Set与List的应用场景

230 阅读4分钟

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 集合的高级特性

  1. 原子性操作

    // Set 的原子性添加(返回是否新增成功)
    boolean added = rSet.addIfAbsent("element");
    
    // List 的原子性操作
    rList.addAndGet(0, "element"); // 在指定位置添加元素
    
  2. 本地缓存

    // 配置本地缓存,减少网络调用
    RLocalCachedSet<String> cachedSet = redisson.getLocalCachedSet(
        "cachedSet", 
        LocalCachedSetOptions.defaults()
    );
    
  3. 异步操作

    // 异步添加元素到 Set
    RFuture<Boolean> future = rSet.addAsync("element");
    future.thenAccept(result -> System.out.println("添加结果: " + result));
    
  4. 事件监听

    // 监听 List 元素变化
    rList.addListener(new ListAddListener<String>() {
        @Override
        public void onListAdd(String element) {
            System.out.println("新增元素: " + element);
        }
    });
    

五、注意事项

  1. 性能考虑

    • List 的随机访问和中间插入性能较差(O(n)),适合头尾操作;
    • Set 的集合运算(如交集)在元素量大时可能影响性能。
  2. 内存占用

    • Redis 是内存数据库,大量数据需谨慎使用,可结合过期策略(如 RListCache)。
  3. 序列化

    • 存储复杂对象时需确保正确实现序列化(如实现 Serializable 接口)。

总结

Redisson 的分布式 Set 和 List 通过 Redis 实现了跨节点的数据共享,结合原子性操作、本地缓存和事件监听等特性,适用于数据去重、消息队列、排行榜等多种场景。选择时需根据业务需求权衡元素唯一性、顺序性和查询效率。