《7天学会Redis》Day 7 - Redisson 全览

本期内容为自己总结归档,7天学会Redis。其中本人遇到过的面试问题会重点标记。

Day 1 - Redis核心架构与线程模型

Day2 - 深入Redis数据结构与底层实现

Day 3 - 持久化机制深度解析

Day 4 - 高可用架构设计与实践

Day 5 - Redis Cluster集群架构

Day 6 - 内存&性能调优

Day 7 - Redisson 框架

(若有任何疑问,可在评论区告诉我,看到就回复)

Day 7 - 一篇讲清楚Redisson 框架

7.1 什么是Redisson,核心定位

⭐Redisson概述

Redisson是一个基于Redis的Java驻内存数据网格(In-Memory Data Grid)客户端,它不仅提供了对Redis基本操作的封装,更重要的是提供了一系列分布式Java对象和服务的实现。Redisson让Java开发者能够在分布式环境中使用类似于Java SE的API。

官方定义:Redisson是架设在Redis基础上的一个Java驻内存数据网格,提供了分布式和可扩展的Java数据结构。

核心定位

Redisson的核心定位可以从四个维度理解:

1. 分布式Java对象

Redisson提供了与Java标准库接口一致的分布式对象,这些对象的数据存储在Redis中,可以被多个JVM实例共享访问。

2. 分布式服务

实现了Java并发包(java.util.concurrent)中的接口,提供分布式版本的锁、信号量、计数器等并发工具。

3. Redis高级客户端

除了基本的Redis命令支持,Redisson还提供了高级功能如连接池管理、负载均衡、故障转移等。

4. 企业级集成框架

与Spring、Spring Boot、Tomcat等主流框架深度集成,提供开箱即用的解决方案。

Redisson vs 原生Redis客户端

特性 原生Redis客户端(Jedis/Lettuce) Redisson
API抽象级别 低级别,直接操作Redis命令 高级别,面向对象API
分布式对象 需要自己实现 内置完整实现
并发工具 需要基于Redis命令封装 内置分布式锁、信号量等
连接管理 基础连接池 智能连接池,支持负载均衡
序列化 需要自己处理 内置多种序列化方案
学习曲线 简单直接 需要学习新API,但更符合Java习惯
适用场景 简单缓存、基础数据结构 复杂分布式系统、需要分布式协调

7.2 Redisson主要功能模块

7.2.1 分布式集合框架

Redisson的分布式集合完全实现了Java集合框架的接口,让开发者可以无缝迁移代码到分布式环境。

RMap - 分布式Map
java 复制代码
// 创建分布式Map
RMap<String, User> map = redisson.getMap("userMap");

// 操作与HashMap完全一致
map.put("user1", new User("张三", 25));
User user = map.get("user1");
map.remove("user1");

// 分布式特性:支持跨JVM的监听器
map.addListener(new EntryCreatedListener<String, User>() {
    @Override
    public void onCreated(EntryEvent<String, User> event) {
        System.out.println("Map条目被创建: " + event.getKey());
    }
});
RList - 分布式List
java 复制代码
RList<String> list = redisson.getList("myList");
list.add("item1");
list.add("item2");
String item = list.get(0);
list.remove(0);
其他分布式集合
  • RSet:分布式Set,支持交集、并集、差集操作

  • RQueue:分布式队列,支持阻塞获取

  • RDeque:分布式双端队列

  • RSortedSet:分布式有序Set

  • RScoredSortedSet:分布式带分数排序Set

7.2.2 分布式锁

⭐RLock - 分布式可重入锁
java 复制代码
RLock lock = redisson.getLock("myLock");

// 尝试加锁,最多等待100秒,上锁后10秒自动解锁
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
    try {
        // 执行业务逻辑
        // 支持可重入:同一线程可重复获取锁
        lock.lock();  // 再次获取,重入次数+1
        // ...
    } finally {
        lock.unlock();  // 释放一次,重入次数-1
        lock.unlock();  // 完全释放锁
    }
}
⭐看门狗机制

关键设计决策

  • 续期间隔TTL/3(默认 30 秒锁,10 秒检查一次),平衡 CPU 开销与安全性

  • 续期失败 :业务线程崩溃,看门狗线程随之终止,锁自动过期,不会死锁

  • 手动指定 TTL :若 lock.lock(10, TimeUnit.SECONDS)不启动看门狗,由业务保证执行时间

⭐RedLock 红锁

争议与生产建议

  • Martin Kleppmann 批评:时钟跳跃、GC 停顿可能导致多个客户端同时持有锁

  • Redis 作者回应 :RedLock 在正确配置 NTP避免 GC 过长场景下可用

  • 生产建议不推荐 在 CAP 强一致性场景使用(金融、支付),推荐允许极低概率失效场景使用(订单、库存)

7.2.3 分布式对象服务

RBucket - 分布式对象存储
java 复制代码
RBucket<User> bucket = redisson.getBucket("userBucket");
bucket.set(new User("李四", 30), 1, TimeUnit.HOURS);  // 设置1小时过期
User user = bucket.get();

// 支持原子操作
bucket.compareAndSet(oldUser, newUser);
其他对象服务
  • RTopic:分布式发布订阅

  • RHyperLogLog:分布式基数统计

  • RBloomFilter:分布式布隆过滤器

  • RBitSet:分布式位图

7.2.4 高级数据结构和算法

Redisson的延迟队列
java 复制代码
RBlockingQueue<String> queue = redisson.getBlockingQueue("myQueue");
RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(queue);

// 延迟10秒将元素放入队列
delayedQueue.offer("task1", 10, TimeUnit.SECONDS);

// 在另一个线程中消费
String task = queue.take();  // 阻塞直到有元素可用
分布式限流器
java 复制代码
RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");
// 每1秒产生2个令牌
rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);

if (rateLimiter.tryAcquire()) {
    // 获取到令牌,执行业务
}

7.2.5 分布式执行服务

Redisson提供了分布式执行服务,可以在多个节点上执行任务。

java 复制代码
// 获取执行服务
RExecutorService executor = redisson.getExecutorService("myExecutor");

// 提交任务
Future<String> future = executor.submit(new CallableTask());
String result = future.get();

// 定义任务
public class CallableTask implements Callable<String>, Serializable {
    @Override
    public String call() throws Exception {
        // 任务逻辑
        return "任务完成";
    }
}

7.3 ⭐Redisson使用场景

7.3.1 分布式锁场景

场景1:防止重复订单提交
java 复制代码
@Service
public class OrderService {
    @Autowired
    private RedissonClient redisson;
    
    public String createOrder(String orderId, String userId) {
        String lockKey = "order:lock:" + orderId;
        RLock lock = redisson.getLock(lockKey);
        
        try {
            // 尝试获取锁,5秒内获取不到则返回false
            if (lock.tryLock(5, 30, TimeUnit.SECONDS)) {
                // 检查订单是否已存在
                if (checkOrderExists(orderId)) {
                    return "订单已存在";
                }
                
                // 创建订单逻辑
                return doCreateOrder(orderId, userId);
            } else {
                return "系统繁忙,请稍后重试";
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return "系统异常";
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
场景2:秒杀库存扣减
java 复制代码
public class SeckillService {
    public boolean seckill(String productId, String userId) {
        String lockKey = "seckill:lock:" + productId;
        RLock lock = redisson.getLock(lockKey);
        
        try {
            // 使用公平锁,保证先到先得
            RLock fairLock = redisson.getFairLock(lockKey);
            
            if (fairLock.tryLock(10, 60, TimeUnit.SECONDS)) {
                try {
                    // 检查库存
                    int stock = getStock(productId);
                    if (stock <= 0) {
                        return false;
                    }
                    
                    // 扣减库存
                    boolean success = decreaseStock(productId);
                    if (success) {
                        // 创建订单
                        createOrder(productId, userId);
                        return true;
                    }
                } finally {
                    fairLock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return false;
    }
}

7.3.2 分布式集合场景

场景:分布式Session共享
java 复制代码
@Configuration
public class SessionConfig {
    
    @Bean
    public MapSessionRepository sessionRepository(RedissonClient redisson) {
        // 使用RMap存储Session
        return new RedissonSessionRepository(redisson);
    }
    
    public class RedissonSessionRepository {
        private final RMap<String, Session> sessionMap;
        
        public RedissonSessionRepository(RedissonClient redisson) {
            this.sessionMap = redisson.getMap("sessions");
        }
        
        public void save(Session session) {
            sessionMap.put(session.getId(), session);
        }
        
        public Session findById(String id) {
            return sessionMap.get(id);
        }
        
        public void deleteById(String id) {
            sessionMap.remove(id);
        }
    }
}

7.3.3 分布式任务调度场景

场景:延迟任务处理
java 复制代码
@Component
public class DelayTaskProcessor {
    @Autowired
    private RedissonClient redisson;
    
    @PostConstruct
    public void init() {
        // 创建延迟队列
        RBlockingQueue<String> queue = redisson.getBlockingQueue("delay:queue");
        RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(queue);
        
        // 启动消费线程
        new Thread(() -> {
            while (true) {
                try {
                    String task = queue.take();
                    processDelayTask(task);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();
    }
    
    public void submitDelayTask(String taskId, long delay, TimeUnit unit) {
        RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(
            redisson.getBlockingQueue("delay:queue")
        );
        delayedQueue.offer(taskId, delay, unit);
    }
    
    private void processDelayTask(String taskId) {
        // 处理延迟任务,如订单超时取消、定时提醒等
        System.out.println("处理延迟任务: " + taskId);
    }
}

7.3.4 分布式限流场景

场景:API限流保护
java 复制代码
@RestController
public class ApiController {
    @Autowired
    private RedissonClient redisson;
    
    @GetMapping("/api/resource")
    public ResponseEntity<?> getResource(@RequestParam String apiKey) {
        String limiterKey = "api:limit:" + apiKey;
        RRateLimiter limiter = redisson.getRateLimiter(limiterKey);
        
        // 设置限流规则:每秒最多10个请求
        limiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);
        
        if (limiter.tryAcquire()) {
            // 执行业务逻辑
            return ResponseEntity.ok(getResourceData());
        } else {
            return ResponseEntity.status(429).body("请求过于频繁,请稍后重试");
        }
    }
}

7.3.5 分布式数据一致性场景

场景:读写锁保证数据一致性
java 复制代码
@Service
public class InventoryService {
    @Autowired
    private RedissonClient redisson;
    
    private RReadWriteLock readWriteLock;
    
    @PostConstruct
    public void init() {
        readWriteLock = redisson.getReadWriteLock("inventory:lock");
    }
    
    // 读取库存(多个读锁可以同时持有)
    public int getInventory(String productId) {
        RLock readLock = readWriteLock.readLock();
        try {
            readLock.lock();
            // 读取库存数据
            return readFromCacheOrDB(productId);
        } finally {
            readLock.unlock();
        }
    }
    
    // 更新库存(写锁排他)
    public boolean updateInventory(String productId, int delta) {
        RLock writeLock = readWriteLock.writeLock();
        try {
            writeLock.lock();
            // 更新库存数据
            return doUpdateInventory(productId, delta);
        } finally {
            writeLock.unlock();
        }
    }
}

7.4 Redisson架构原理深度解析

7.4.1 连接管理与负载均衡

Redisson使用Netty作为网络通信框架,支持多种连接管理模式:

连接池配置

java 复制代码
Config config = new Config();
config.useSingleServer()
      .setAddress("redis://127.0.0.1:6379")
      .setConnectionPoolSize(64)      // 最大连接数
      .setConnectionMinimumIdleSize(10) // 最小空闲连接数
      .setConnectTimeout(10000)       // 连接超时时间
      .setTimeout(3000)               // 命令超时时间
      .setRetryAttempts(3)            // 重试次数
      .setRetryInterval(1500);        // 重试间隔

7.4.2 序列化机制

Redisson支持多种序列化方案,可根据业务需求选择:

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

// 1. Jackson序列化(推荐)
config.setCodec(new JsonJacksonCodec());

// 2. FST序列化(高性能)
config.setCodec(new FstCodec());

// 3. Kryo序列化(性能好,但需要注册类)
KryoCodec kryoCodec = new KryoCodec();
kryoCodec.registerClass(User.class);
config.setCodec(kryoCodec);

// 4. 自定义序列化
config.setCodec(new SerializationCodec() {
    @Override
    protected ObjectDecoder createValueDecoder(ClassLoader classLoader) {
        return new CustomDecoder();
    }
    
    @Override
    protected ObjectEncoder createValueEncoder() {
        return new CustomEncoder();
    }
});

7.4.3 发布订阅机制

Redisson使用Redis的Pub/Sub功能实现事件通知:

java 复制代码
// 发布者
RTopic topic = redisson.getTopic("myTopic");
topic.publish(new Message("Hello, World!"));

// 订阅者
topic.addListener(Message.class, (channel, msg) -> {
    System.out.println("收到消息: " + msg);
});

// 分布式锁释放通知的实现
public class LockPubSub extends PublishSubscribe<LockMessage> {
    @Override
    protected LockMessage decode(ByteBuf buf, Codec codec) {
        // 解码锁消息
        return codec.getValueDecoder().decode(buf, null);
    }
    
    @Override
    protected void onMessage(LockMessage message) {
        // 处理锁释放通知
        if (message instanceof LockReleasedMessage) {
            // 通知等待锁的线程
            notifyLockReleased();
        }
    }
}

7.4.5 Redisson分布式锁知识体系

7.5 Redisson与Spring生态集成

7.5.1 Spring Boot自动配置

bash 复制代码
# application.yml
spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: "redis://127.0.0.1:6379"
          password: null
          database: 0
          connectionPoolSize: 64
          connectionMinimumIdleSize: 10
          subscriptionConnectionPoolSize: 50
          dnsMonitoringInterval: 5000
        codec: !<org.redisson.codec.JsonJacksonCodec> {}
        threads: 16
        nettyThreads: 32

7.5.2 Spring Cache集成

java 复制代码
@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) {
        Map<String, CacheConfig> config = new HashMap<>();
        
        // 配置用户缓存
        config.put("userCache", new CacheConfig(
            30 * 60 * 1000,  // 30分钟过期
            1000             // 最大缓存数量
        ));
        
        return new RedissonSpringCacheManager(redissonClient, config);
    }
}

@Service
public class UserService {
    @Cacheable(value = "userCache", key = "#userId")
    public User getUser(String userId) {
        // 数据库查询
        return userRepository.findById(userId);
    }
    
    @CachePut(value = "userCache", key = "#user.id")
    public User updateUser(User user) {
        // 更新数据库
        return userRepository.save(user);
    }
    
    @CacheEvict(value = "userCache", key = "#userId")
    public void deleteUser(String userId) {
        userRepository.deleteById(userId);
    }
}

7.5.3 Spring Session集成

java 复制代码
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {
    
    @Bean
    public RedissonConnectionFactory redissonConnectionFactory(
            RedissonClient redisson) {
        return new RedissonConnectionFactory(redisson);
    }
    
    @Bean
    public HttpSessionIdResolver httpSessionIdResolver() {
        // 使用Cookie和Header双重方式传递Session ID
        return new HeaderHttpSessionIdResolver("X-Auth-Token");
    }
}

7.6 ⭐面试高频考点

考点1:⭐Redisson分布式锁的实现原理?

面试回答:

Redisson分布式锁的实现基于Redis的Hash数据结构和Lua脚本,核心原理包括:

  1. 可重入机制:使用Hash结构存储锁信息,key为锁名称,field为客户端标识(UUID + threadId),value为重入次数。同一线程可重复获取锁,每次获取重入次数加1。

  2. 看门狗自动续期:获取锁成功后,启动后台线程(看门狗)定期(默认10秒)检查锁是否仍被持有,如果是则重置过期时间为30秒,防止业务执行时间过长导致锁过期。

  3. Lua脚本保证原子性:所有锁操作(加锁、解锁、续期)都使用Lua脚本执行,确保原子性,避免竞态条件。

  4. 公平锁实现:通过Redis的List结构维护等待队列,结合发布订阅机制通知等待的客户端,实现先到先得的公平锁。

  5. 解锁安全:解锁时检查客户端标识,确保只有加锁的客户端才能解锁,避免误解锁。

加锁Lua脚本关键逻辑:

lua

复制代码
-- 如果锁不存在,创建锁并设置重入次数为1
-- 如果锁已存在且是同一客户端,重入次数加1
-- 如果锁被其他客户端持有,返回锁的剩余生存时间

考点2:Redisson与Jedis、Lettuce的区别?

面试回答:

特性 Jedis Lettuce Redisson
API级别 低级别,Redis命令封装 低级别,响应式支持 高级别,分布式对象抽象
连接管理 连接池,阻塞I/O 单连接多路复用,非阻塞I/O 连接池,基于Netty的非阻塞I/O
线程安全 非线程安全,需用连接池 线程安全,连接可共享 线程安全,内置连接管理
分布式支持 无,需自己实现 无,需自己实现 内置分布式锁、集合、服务等
序列化 需要自己处理 需要自己处理 内置多种序列化方案
适用场景 简单同步操作 高并发,响应式编程 复杂分布式系统,需要分布式协调
学习成本 较高(需要学习新API)

核心区别:Jedis和Lettuce是Redis客户端,主要提供Redis命令操作;Redisson是基于Redis的分布式服务框架,提供了更高层次的抽象和分布式原语。

考点3:⭐Redisson的看门狗机制如何工作?

面试回答:

Redisson的看门狗(Watchdog)机制是防止分布式锁过期的重要保障,工作流程如下:

  1. 触发时机 :当使用lock()方法获取锁时(未指定leaseTime参数),看门狗机制会自动启用。

  2. 续期逻辑

    • 获取锁成功后,启动一个后台定时任务

    • 默认每10秒(锁超时时间的1/3)执行一次续期检查

    • 检查锁是否还被当前线程持有,如果是则将锁过期时间重置为30秒

  3. 自动停止

    • 锁被正常释放时,看门狗任务会自动取消

    • 客户端宕机时,看门狗任务随进程终止,锁最终会因超时自动释放

  4. 配置参数

    java

    复制代码
    Config config = new Config();
    config.setLockWatchdogTimeout(30000); // 设置看门狗超时时间,默认30秒

注意事项

  • 使用tryLock(leaseTime, unit)指定租约时间时,看门狗不会启动

  • 看门狗机制增加了Redis的负载,需合理设置超时时间

  • 网络分区时可能造成锁被多个客户端持有,需结合业务处理

相关推荐
马尔代夫哈哈哈2 小时前
Spring IoC&DI
数据库·sql
液态不合群4 小时前
[特殊字符] MySQL 覆盖索引详解
数据库·mysql
virus59454 小时前
悟空CRM mybatis-3.5.3-mapper.dtd错误解决方案
java·开发语言·mybatis
计算机毕设VX:Fegn08955 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
瀚高PG实验室5 小时前
PostgreSQL到HighgoDB数据迁移
数据库·postgresql·瀚高数据库
打码人的日常分享6 小时前
智能制造数字化工厂解决方案
数据库·安全·web安全·云计算·制造
没差c6 小时前
springboot集成flyway
java·spring boot·后端
三水不滴6 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
时艰.6 小时前
Java 并发编程之 CAS 与 Atomic 原子操作类
java·开发语言
编程彩机6 小时前
互联网大厂Java面试:从Java SE到大数据场景的技术深度解析
java·大数据·spring boot·面试·spark·java se·互联网大厂