Redisson详解:高性能redis客户端,超详细!

一、Redisson介绍

Redisson是一个在Redis基础上实现的Java驻内存数据网格。它不仅提供了一系列的分布式和可扩展的Java数据结构,还提供了许多分布式服务。Redisson作为Redis的Java客户端,不仅仅是一个简单的Redis连接池,而是一个功能丰富的分布式和可扩展的Java数据结构集合。

Redisson的主要特点包括:

  • 基于Netty框架实现,支持异步和同步操作
  • 提供了分布式和可扩展的Java数据结构
  • 内置高性能分布式缓存解决方案
  • 支持Redis的多种部署模式(单机、主从、哨兵、集群)
  • 内置了多种分布式锁实现
  • 提供了丰富的分布式服务(如分布式调度任务、分布式MapReduce等)

二、Redisson的核心特性

分布式对象

Redisson提供了多种分布式对象,这些对象在Redis中都有对应的实现:

复制代码
// 获取Redisson客户端实例
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);

// 分布式对象示例
RList<String> list = redisson.getList("myList");  // 分布式List
RSet<String> set = redisson.getSet("mySet");      // 分布式Set
RMap<String, String> map = redisson.getMap("myMap"); // 分布式Map
RBucket<String> bucket = redisson.getBucket("myBucket"); // 分布式Bucket

三、Redisson缓存存储详解

Redisson提供了强大的分布式缓存解决方案,包括多种缓存策略、缓存加载机制和缓存事件监听等功能。

1. 基本缓存操作(RBucket)

RBucket是Redisson中最基本的缓存存储单元,用于存储单个对象:

复制代码
// 获取Bucket对象
RBucket<User> userBucket = redisson.getBucket("user:1001");

// 存储对象到缓存
User user = new User(1001, "张三", "zhangsan@example.com");
userBucket.set(user);

// 设置过期时间(1小时后过期)
userBucket.set(user, 1, TimeUnit.HOURS);

// 从缓存获取对象
User cachedUser = userBucket.get();
System.out.println("从缓存获取用户: " + cachedUser);

// 删除缓存
userBucket.delete();

// 检查缓存是否存在
boolean exists = userBucket.isExists();

2. 分布式Map缓存(RMapCache)

RMapCache是带有过期功能的分布式Map,适合用作缓存存储:

复制代码
// 获取带过期功能的Map
RMapCache<String, User> userMapCache = redisson.getMapCache("userMapCache");

// 存储对象并设置过期时间(30分钟后过期)
User user1 = new User(1001, "张三", "zhangsan@example.com");
userMapCache.put("1001", user1, 30, TimeUnit.MINUTES);

// 存储对象并设置最大空闲时间(10分钟内没有被访问则过期)
User user2 = new User(1002, "李四", "lisi@example.com");
userMapCache.put("1002", user2, 1, TimeUnit.HOURS, 10, TimeUnit.MINUTES);

// 获取对象
User cachedUser = userMapCache.get("1001");
if (cachedUser != null) {
    System.out.println("从缓存获取用户: " + cachedUser);
}

// 获取所有键
Collection<String> keys = userMapCache.keySet();

// 移除特定键
userMapCache.remove("1002");

// 清空缓存
userMapCache.clear();

3. 缓存加载器(自动加载)

Redisson支持通过CacheLoader自动加载缓存,当缓存不存在时自动从数据源加载:

复制代码
// 创建带缓存加载器的MapCache
RMapCache<String, User> userMapCache = redisson.getMapCache("userMapCache");

// 模拟从数据库加载用户数据
CacheLoader<String, User> loader = key -> {
    System.out.println("从数据库加载用户: " + key);
    // 这里应该是从数据库查询的逻辑
    if ("1001".equals(key)) {
        return new User(1001, "张三", "zhangsan@example.com");
    } else if ("1002".equals(key)) {
        return new User(1002, "李四", "lisi@example.com");
    }
    return null;
};

// 获取对象,如果不存在则自动加载
User user = userMapCache.getOrDefault("1001", loader);
System.out.println("获取用户: " + user);

// 再次获取,这次会从缓存读取
User cachedUser = userMapCache.getOrDefault("1001", loader);
System.out.println("再次获取用户(应来自缓存): " + cachedUser);

4. 多级缓存策略

Redisson可以与本地缓存结合实现多级缓存:

复制代码
// 本地缓存(Caffeine示例)
Cache<String, User> localCache = Caffeine.newBuilder()
        .expireAfterWrite(1, TimeUnit.MINUTES) // 本地缓存1分钟
        .maximumSize(1000)
        .build();

// Redis分布式缓存
RMapCache<String, User> redisCache = redisson.getMapCache("userCache");

// 多级缓存获取
public User getUserWithMultiLevelCache(String userId) {
    // 1. 先查本地缓存
    User user = localCache.getIfPresent(userId);
    if (user != null) {
        System.out.println("从本地缓存获取用户: " + userId);
        return user;
    }
    
    // 2. 查Redis分布式缓存
    user = redisCache.get(userId);
    if (user != null) {
        System.out.println("从Redis缓存获取用户: " + userId);
        // 回填本地缓存
        localCache.put(userId, user);
        return user;
    }
    
    // 3. 查数据库(模拟)
    System.out.println("从数据库加载用户: " + userId);
    user = loadFromDatabase(userId);
    if (user != null) {
        // 写入Redis缓存(设置30分钟过期)
        redisCache.put(userId, user, 30, TimeUnit.MINUTES);
        // 写入本地缓存
        localCache.put(userId, user);
    }
    
    return user;
}

// 模拟数据库加载
private User loadFromDatabase(String userId) {
    // 实际应用中这里是从数据库查询
    if ("1001".equals(userId)) {
        return new User(1001, "张三", "zhangsan@example.com");
    }
    return null;
}

5. 缓存事件监听

Redisson支持监听缓存事件,如缓存添加、移除等:

复制代码
// 获取MapCache
RMapCache<String, User> userMapCache = redisson.getMapCache("userMapCache");

// 添加缓存事件监听器
userMapCache.addListener(new EntryAddedListener<String, User>() {
    @Override
    public void onCreated(EntryEvent<String, User> event) {
        System.out.println("缓存添加事件 - Key: " + event.getKey() + ", Value: " + event.getValue());
    }
});

userMapCache.addListener(new EntryRemovedListener<String, User>() {
    @Override
    public void onRemoved(EntryEvent<String, User> event) {
        System.out.println("缓存移除事件 - Key: " + event.getKey() + ", Value: " + event.getValue());
    }
});

// 触发事件
userMapCache.put("1001", new User(1001, "张三", "zhangsan@example.com"));
userMapCache.remove("1001");

6. 缓存统计信息

Redisson提供了缓存统计功能,可以监控缓存命中率等指标:

复制代码
// 获取带统计功能的MapCache
RMapCache<String, User> statsMapCache = redisson.getMapCache("statsMapCache");

// 启用统计(需要Redisson配置中启用)
// statsMapCache = redisson.getMapCache("statsMapCache", 
//     new MapOptions<String, User>().statisticsEnabled(true));

// 存储数据
statsMapCache.put("1001", new User(1001, "张三", "zhangsan@example.com"));

// 注意:获取统计信息需要通过Redis命令或管理工具
// 实际应用中可以通过Redis的INFO命令或Redisson的管理API获取

四、Redisson缓存高级特性

1. 缓存预热

在应用启动时预先加载热点数据到缓存:

复制代码
@PostConstruct
public void initCache() {
    // 应用启动时预热热门用户数据
    List<String> hotUserIds = Arrays.asList("1001", "1002", "1003");
    for (String userId : hotUserIds) {
        User user = loadFromDatabase(userId);
        if (user != null) {
            userMapCache.put(userId, user, 2, TimeUnit.HOURS);
        }
    }
}

2. 缓存雪崩防护

通过为不同的缓存项设置随机的过期时间,避免大量缓存同时失效:

复制代码
// 为不同的用户设置基础过期时间+随机偏移量,避免雪崩
public void cacheUserWithAvalancheProtection(User user) {
    long baseTtl = 30; // 基础30分钟
    long randomOffset = ThreadLocalRandom.current().nextLong(0, 10); // 随机0-10分钟偏移
    long ttl = baseTtl + randomOffset;
    
    userMapCache.put(user.getId().toString(), user, ttl, TimeUnit.MINUTES);
}

3. 缓存穿透防护

对于不存在的key也进行缓存,避免频繁查询数据库:

复制代码
public User getUserWithPenetrationProtection(String userId) {
    // 1. 先查缓存
    User user = userMapCache.get(userId);
    
    if (user != null) {
        // 缓存命中,如果是特殊标记的空值,返回null
        if (user instanceof NullUser) {
            return null;
        }
        return user;
    }
    
    // 2. 查数据库
    user = loadFromDatabase(userId);
    
    if (user != null) {
        // 3. 数据库存在,写入缓存
        userMapCache.put(userId, user, 30, TimeUnit.MINUTES);
    } else {
        // 4. 数据库不存在,缓存空值防止穿透
        userMapCache.put(userId, new NullUser(), 5, TimeUnit.MINUTES);
    }
    
    return user;
}

// 空值标记类
private static class NullUser extends User {
    public NullUser() {
        super(-1, null, null);
    }
}

4. 缓存击穿防护(互斥锁)

使用分布式锁防止热点key失效时大量请求直接打到数据库:

复制代码
public User getUserWithBreakdownProtection(String userId) {
    String lockKey = "user_lock:" + userId;
    RLock lock = redisson.getLock(lockKey);
    
    try {
        // 1. 先查缓存
        User user = userMapCache.get(userId);
        if (user != null) {
            if (user instanceof NullUser) {
                return null;
            }
            return user;
        }
        
        // 2. 获取分布式锁
        boolean locked = lock.tryLock(1, 10, TimeUnit.SECONDS);
        if (locked) {
            try {
                // 双重检查,可能在等待锁的过程中其他线程已经加载了缓存
                user = userMapCache.get(userId);
                if (user != null) {
                    if (user instanceof NullUser) {
                        return null;
                    }
                    return user;
                }
                
                // 3. 查数据库
                user = loadFromDatabase(userId);
                
                if (user != null) {
                    // 4. 写入缓存
                    userMapCache.put(userId, user, 30, TimeUnit.MINUTES);
                } else {
                    // 5. 缓存空值
                    userMapCache.put(userId, new NullUser(), 5, TimeUnit.MINUTES);
                }
                
                return user;
            } finally {
                lock.unlock();
            }
        } else {
            // 获取锁失败,短暂等待后重试
            Thread.sleep(100);
            return getUserWithBreakdownProtection(userId);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new RuntimeException("获取用户信息被中断", e);
    }
}

五、Redisson配置详解(补充缓存相关配置)

1. 缓存配置选项

复制代码
Config config = new Config();

// 单机模式配置
config.useSingleServer()
      .setAddress("redis://127.0.0.1:6379")
      .setPassword("password");

// 缓存相关配置(通过MapOptions设置)
MapOptions<String, User> mapOptions = MapOptions.<String, User>defaults()
    .evictionPolicy(EvictionPolicy.LRU) // 淘汰策略: LRU, LFU, FIFO
    .maxSize(1000) // 最大缓存条目数
    .timeToLive(30, TimeUnit.MINUTES) // 条目存活时间
    .maxIdle(10, TimeUnit.MINUTES); // 条目最大空闲时间

// 创建带配置的MapCache
RMapCache<String, User> userMapCache = redisson.getMapCache("userMapCache", mapOptions);

2. 淘汰策略

Redisson支持多种缓存淘汰策略:

复制代码
// LRU (最近最少使用)
MapOptions<String, User> lruOptions = MapOptions.<String, User>defaults()
    .evictionPolicy(EvictionPolicy.LRU);

// LFU (最不经常使用)
MapOptions<String, User> lfuOptions = MapOptions.<String, User>defaults()
    .evictionPolicy(EvictionPolicy.LFU);

// FIFO (先进先出)
MapOptions<String, User> fifoOptions = MapOptions.<String, User>defaults()
    .evictionPolicy(EvictionPolicy.FIFO);

集群配置:

1.单机模式
复制代码
Config config = new Config();

// 单机模式
config.useSingleServer()
      .setAddress("redis://127.0.0.1:6379")
      .setPassword("password")
      .setDatabase(0)
      .setConnectionPoolSize(64) // 连接池大小
      .setConnectionMinimumIdleSize(10) // 最小空闲连接数
      .setIdleConnectionTimeout(10000) // 空闲连接超时时间
      .setConnectTimeout(10000) // 连接超时时间
      .setTimeout(3000) // 命令等待超时时间
      .setRetryAttempts(3) // 命令重试次数
      .setRetryInterval(1500) // 命令重试发送时间间隔
      .setPingConnectionInterval(30000) // 连接空闲多久后发送ping命令保持连接
      .setKeepAlive(true); // 是否保持长连接

RedissonClient redisson = Redisson.create(config);
2. 主从模式配置
复制代码
Config config = new Config();
config.useMasterSlaveServers()
      .setMasterAddress("redis://127.0.0.1:6379")
      .addSlaveAddress("redis://127.0.0.1:6380", "redis://127.0.0.1:6381")
      .setPassword("password")
      .setDatabase(0)
      .setSlaveConnectionPoolSize(64)
      .setMasterConnectionPoolSize(64)
      .setReadMode(ReadMode.SLAVE) // 读操作从从节点读取
      .setSubscriptionMode(SubscriptionMode.SLAVE); // 订阅操作从从节点读取

RedissonClient redisson = Redisson.create(config);
3. 哨兵模式配置
复制代码
Config config = new Config();
config.useSentinelServers()
      .setMasterName("mymaster")
      .addSentinelAddress("redis://127.0.0.1:26379", "redis://127.0.0.1:26380")
      .setPassword("password")
      .setDatabase(0)
      .setMasterConnectionPoolSize(64)
      .setSlaveConnectionPoolSize(64);

RedissonClient redisson = Redisson.create(config);
4. 集群模式配置
复制代码
Config config = new Config();
config.useClusterServers()
      .addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
      .addNodeAddress("redis://127.0.0.1:7002", "redis://127.0.0.1:7003")
      .addNodeAddress("redis://127.0.0.1:7004", "redis://127.0.0.1:7005")
      .addNodeAddress("redis://127.0.0.1:7006", "redis://127.0.0.1:7007")
      .setPassword("password")
      .setScanInterval(2000) // 集群状态扫描间隔时间
      .setSlaveConnectionPoolSize(64)
      .setMasterConnectionPoolSize(64);

RedissonClient redisson = Redisson.create(config);

六、Redisson缓存最佳实践

1. 缓存设计原则

  • 合理设置缓存粒度 :根据业务需求确定缓存对象的大小和粒度
  • 选择合适的过期策略 :根据数据特性设置合理的TTL和最大空闲时间
  • 避免大Key :单个缓存值不宜过大,建议控制在10MB以内
  • 考虑数据一致性 :明确缓存与数据库的一致性要求

2. 性能优化建议

  • 批量操作 :尽可能使用批量操作减少网络往返
  • 异步操作 :对于非关键路径使用异步缓存操作
  • 本地缓存结合 :热点数据可结合本地缓存实现多级缓存
  • 监控缓存命中率 :定期分析缓存命中率,优化缓存策略

3. 监控与维护

  • 监控缓存指标 :关注缓存大小、命中率、淘汰率等指标
  • 定期清理 :对于长期不用的缓存数据定期清理
  • 容量规划 :根据业务增长预测缓存容量需求

Redisson不仅提供了强大的分布式数据结构支持,还通过其分布式缓存解决方案(如RBucket、RMapCache等)为Java应用提供了高性能、易用的缓存存储能力。通过本文的介绍,我们深入了解了Redisson的缓存存储功能,包括:

  1. 基本缓存操作 :通过RBucket实现简单的键值缓存
  2. 高级缓存功能 :通过RMapCache实现带过期策略的分布式Map缓存
  3. 缓存加载机制 :自动从数据源加载缓存的CacheLoader
  4. 多级缓存策略 :结合本地缓存实现高效的多级缓存
  5. 缓存事件监听 :监听缓存变化事件
  6. 缓存保护机制 :防止缓存雪崩、穿透、击穿等问题的策略