Redisson分布式利器-常用功能入门与实践
目录一、学习背景与目标1.1 学习背景1.2 学习目标二、核心概念与原理2.1 什么是 Redisson2.2 看门狗机制Watch Dog2.3 RedLock 算法三、逻辑图谱与对比3.1 关系图谱3.2 核心组件对比分布式锁三兄弟分布式队列对比3.3 决策流程图四、核心详解4.1 基础配置引入依赖获取 RedissonClient4.2 RLock —— 分布式可重入锁最常用场景互斥访问共享资源最标准的用法模板公平锁4.3 RReadWriteLock —— 分布式读写锁场景缓存和数据库的一致性4.4 RSemaphore —— 分布式信号量场景限制并发数如限制同时只能有 10 个任务执行4.5 RRateLimiter —— 分布式限流器场景按某个速率限制接口的调用频率4.6 RMapCache —— 带缓存淘汰的分布式 Map场景多节点共享缓存自动过期4.7 RQueue / RBlockingQueue / RDelayedQueue简单的分布式队列阻塞队列生产者-消费者模式延迟队列如订单超时取消4.8 RTopic —— 发布订阅场景轻量级广播通知五、典型应用案例5.1 案例分布式锁扣库存最经典场景5.2 案例双 11 接口限流RateLimiter5.3 案例延迟队列实现订单超时自动取消5.4 案例分布式读写锁 本地缓存解决缓存击穿六、常见坑与最佳实践6.1 易错点清单6.2 异常处理模板6.3 最佳实践清单七、总结与学习路线图7.1 知识点提炼核心口诀核心要点速览自检清单7.2 反思与后续规划推荐延伸阅读一句话读懂Redisson 是 Redis 的 Java 智能客户端把分布式场景下最头疼的「锁、队列、限流、缓存一致性」问题封装成了像本地代码一样调用的 API。学完它你的项目就有了一个开箱即用的分布式工具箱。 适合人群有 Java 基础 了解 Redis 基本数据结构String/Hash/List的开发者 难度等级⭐⭐☆☆☆入门 ⏱阅读时长约 15 分钟 前置知识Spring Boot 基础、Redis 基本操作、Maven/Gradle一、学习背景与目标1.1 学习背景项目从单机走向分布式第一个碰到的问题永远是单机版synchronized → 同一JVM内互斥完美好用 分布式多台机器同时跑 → synchronized 跨JVM失效 → 数据竞争于是开始自己撸分布式锁// 自己写的 Redis 分布式锁 V1.0未上生产版 if (OK.equals(jedis.set(key, value, NX, EX, 30))) { try { // 业务逻辑 } finally { jedis.del(key); // 问题可能删掉别人的锁 } }上面这段代码存在三个经典问题锁过期释放业务没跑完锁就过期了误删他人锁锁过期后别的线程拿到锁当前线程释放时把别人的锁删了无可重入同一线程递归调用会死锁这只是锁一个场景。往上加还有分布式限流、分布式队列、分布式计数器、缓存一致性……每个场景都自己手写一遍代码量爆炸、坑多、维护成本高。Redisson 就是来解决这个问题的。它把这些分布式基础设施都封装好了API 长得跟本地 API 一模一样开箱即用。1.2 学习目标读完本篇后你能做到✅ 掌握分布式锁可重入 自动续期 RedLock能用一到两种锁解决生产问题✅ 掌握分布式限流能用 RateLimiter 保护下游接口不被突增请求打垮✅ 掌握分布式队列 发布订阅能用 RQueue / RMapCache 替代简单的 MQ 场景✅ 理解Redisson 的看门狗机制知道为什么它比手写的 Redis 锁可靠✅ 知道常见坑在哪里怎么避二、核心概念与原理2.1 什么是 Redisson一句话定义Redisson 是 Redis 官方推荐的 Java 客户端之一与 Jedis、Lettuce 并列它最大的亮点是把 Redis 的数据结构「翻译」成了 Java 开发者熟悉的并发工具和集合类。定位对比客户端定位适合场景Jedis底层 Redis 客户端API 贴近 Redis 命令对 Redis 做基础 CRUDLettuce异步/响应式 Redis 客户端高并发、响应式架构Redisson分布式工具集封装了锁、队列、限流等分布式应用开发Redisson 不是让你「操作 Redis 的」而是让你「用 Java API 搞定分布式问题」的。2.2 看门狗机制Watch Dog这是 Redisson 分布式锁的核心竞争力必须弄懂。问题手写 Redis 锁时设置过期时间为 30 秒。如果业务执行了 60 秒锁在 30 秒时自动释放别的线程进来了——数据竞争。Redisson 的解法看门狗。线程获取锁 → 默认过期时间 30 秒 → 后台启动一个定时线程看门狗 → 每 10 秒检查一次锁是否还在 → 还在的话就把过期时间重置为 30 秒 → 业务执行完毕释放锁 → 看门狗退出一句话记住看门狗 自动续期保证锁不因业务还没跑完就被释放。⚠️ 如果你手动指定了锁的超时时间lock(10, TimeUnit.SECONDS)看门狗就不会启动——因为你已经显式指定了过期策略。2.3 RedLock 算法背景单节点 Redis 挂了锁就没了。但如果部署主从主节点挂了之后锁信息还没同步到从节点另一个线程同样能拿到锁。RedLock 解法在 N 个独立的 Redis 节点上同时加锁只有超过半数N/2 1节点加锁成功才算获取到锁。Redisson 内置实现了 RedLock使用方式几乎和普通锁一样。一句话记住RedLock 解决的是「Redis 节点宕机导致锁失效」的问题适用于对锁可靠性要求极高的场景。三、逻辑图谱与对比3.1 关系图谱Redisson 总体脉络 │ ├─ 分布式对象Distributed Objects │ ├─ RMap / RMapCache → 分布式 Map支持缓存淘汰 │ ├─ RSet / RList → 分布式 Set / List │ └─ RBucket → 任意对象的分布式存储 │ ├─ 分布式锁Locks Synchronizers │ ├─ RLock → 可重入锁最常用 │ ├─ RReadWriteLock → 读写锁读多写少场景 │ ├─ RSemaphore → 信号量限流/资源池 │ ├─ RCountDownLatch → 倒计数器等待多个节点完成 │ └─ RRateLimiter → 限流器漏桶算法 │ ├─ 分布式消息Distributed Messaging │ ├─ RQueue → 分布式无界队列 │ ├─ RDelayedQueue → 延迟队列 │ ├─ RBlockingQueue → 阻塞队列如 RabbitMQ 替代 │ └─ RTopic → 发布订阅模式 │ └─ 分布式计算Distributed Computing ├─ RExecutorService → 分布式执行器 └─ RRemoteService → 远程服务调用3.2 核心组件对比分布式锁三兄弟对比维度RLock可重入锁RReadWriteLock读写锁RSemaphore信号量定位独占互斥读共享/写独占资源数量控制可重入✅✅❌场景扣库存、下单互斥缓存刷新读多写少限流、资源池看门狗✅✅❌使用频率⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐分布式队列对比对比维度RQueueRBlockingQueueRDelayedQueue是否阻塞❌ 轮询✅ 阻塞等待✅ 延迟后出队替代场景简单消息RabbitMQ 初级替代订单超时取消使用复杂度⭐⭐⭐⭐⭐⭐3.3 决策流程图遇到分布式同步需求 │ ├─ 需要互斥访问 → 选 RLock │ ├─ 读多写少 → RReadWriteLock │ ├─ 需要限制并发数 → RSemaphore │ └─ 高可靠性跨Redis节点 → RedLock │ ├─ 需要限流 → 选 RRateLimiter │ ├─ 接口级别限流 → 结合 AOP 注解 │ └─ 全局限流 → 全局 RateLimiter │ ├─ 需要队列 → 选 RQueue / RBlockingQueue / RDelayedQueue │ ├─ 即时、简单、低要求 → RQueue │ ├─ 需要生产-消费阻塞等待 → RBlockingQueue │ └─ 需要延迟处理 → RDelayedQueue │ └─ 需要缓存一致性 → 选 RMapCache / RLocalCachedMap四、核心详解4.1 基础配置引入依赖!-- Spring Boot 项目配合 redisson-spring-boot-starter-- dependency groupIdorg.redisson/groupId artifactIdredisson-spring-boot-starter/artifactId version3.27.2/version /dependency # application.yml spring: data: redis: host: 192.168.1.100 port: 6379 password: 123456 database: 0获取 RedissonClientAutowired private RedissonClient redissonClient;也可以手动构建Config对象用于单机、哨兵、集群但spring-boot-starter自动注入就够用了。4.2 RLock —— 分布式可重入锁最常用场景互斥访问共享资源一句话记住方法参数功能⚠️ 注意事项不传时间 看门狗自动续期lock()无获取锁阻塞直到成功默认 30s 续期一定要在 finally 解锁指定等待时间 拿不到就放弃tryLock(waitTime, leaseTime, unit)waitTime 等待时长leaseTime 锁持有时长尝试获取锁leaseTime0 时看门狗不启动解锁要放在 finallyunlock()无释放锁必须先获取锁才能解锁否则抛异常最标准的用法模板RLock lock redissonClient.getLock(order:lock: orderId); // 方式一自动续期推荐 lock.lock(); // 阻塞直到获取到锁看门狗自动 30 秒续期 try { // 业务逻辑 doBusiness(); } finally { lock.unlock(); } // 方式二手动指定超时看门狗不启动 if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { // 等待5秒持有10秒 try { doBusiness(); } finally { lock.unlock(); } }公平锁// 公平锁按请求顺序获取锁 RLock fairLock redissonClient.getFairLock(order:fair: orderId);4.3 RReadWriteLock —— 分布式读写锁场景缓存和数据库的一致性场景获取行为读-读读锁不互斥并发读读-写写锁写锁等待读锁释放写-写写锁互斥写-读读锁读锁等待写锁释放RReadWriteLock rwLock redissonClient.getReadWriteLock(cache:rw:config); RLock readLock rwLock.readLock(); RLock writeLock rwLock.writeLock(); // 读 readLock.lock(); try { return cache.get(config); } finally { readLock.unlock(); } // 写如刷新配置 writeLock.lock(); try { cache.put(config, newConfig); } finally { writeLock.unlock(); }4.4 RSemaphore —— 分布式信号量场景限制并发数如限制同时只能有 10 个任务执行RSemaphore semaphore redissonClient.getSemaphore(semaphore:task); // 初始化设置信号量总量 semaphore.trySetPermits(10); // 获取许可 try { semaphore.acquire(); // 获取不到则阻塞 // 执行业务 } finally { semaphore.release(); }4.5 RRateLimiter —— 分布式限流器场景按某个速率限制接口的调用频率RRateLimiter rateLimiter redissonClient.getRateLimiter(rate:api:order); // 速率每 5 秒产生 10 个许可漏桶算法 rateLimiter.trySetRate(RateType.OVERALL, 10, 5, RateIntervalUnit.SECONDS); // 尝试获取许可 if (rateLimiter.tryAcquire(1)) { // 放行 return handleRequest(); } else { // 限流 return 请求过于频繁请稍后再试; }RateType.OVERALL全局限流所有客户端共享。RateType.PER_CLIENT每个客户端独立4.6 RMapCache —— 带缓存淘汰的分布式 Map场景多节点共享缓存自动过期RMapCacheString, Object cache redissonClient.getMapCache(cache:user); // TTL、最大空闲时间、最大容量 cache.put(user:1001, userObj, 10, TimeUnit.MINUTES, 5, TimeUnit.MINUTES); // 最大容量LRU 淘汰 cache.put(user:1002, userObj2); // 当缓存超过 1000 条目时按 LRU 淘汰 cache.setMaxSize(1000);对比 Redis 原生用法对比Redis 原生Redisson RMapCache写入SET / HSET EXPIREput(key, value, ttl, ...)读取GET / HGETget(key)过期清理Redis 自动Redis 自动客户端无感本地缓存❌✅ RLocalCachedMap 支持4.7 RQueue / RBlockingQueue / RDelayedQueue简单的分布式队列// 生产者 RQueueString queue redissonClient.getQueue(queue:task); queue.add(task_001); // 消费者 String task queue.poll(); // 非阻塞阻塞队列生产者-消费者模式// 消费者端阻塞等待 RBlockingQueueString blockingQueue redissonClient.getBlockingQueue(queue:blocking); while (true) { String task blockingQueue.take(); // 阻塞直到有消息 process(task); }延迟队列如订单超时取消RBlockingQueueString blockingQueue redissonClient.getBlockingQueue(queue:order:delay); RDelayedQueueString delayedQueue redissonClient.getDelayedQueue(blockingQueue); // 放入延迟任务30 分钟后自动转入 blockingQueue delayedQueue.offer(order_1001, 30, TimeUnit.MINUTES); // 消费者阻塞等待 new Thread(() - { while (true) { String orderId blockingQueue.take(); // 30分钟后才能拿到 cancelOrder(orderId); } }).start();4.8 RTopic —— 发布订阅场景轻量级广播通知// 发布者 RTopic topic redissonClient.getTopic(topic:notify); topic.publish(订单已支付:1001); // 订阅者 topic.addListener(String.class, (channel, msg) - { System.out.println(收到消息: msg); });五、典型应用案例5.1 案例分布式锁扣库存最经典场景 需求描述在高并发下保证库存不被超卖。多个订单服务实例同时扣同个 SKU 的库存。 实现代码Service public class StockService { Autowired private RedissonClient redissonClient; public boolean reduceStock(Long skuId, Integer quantity) { String lockKey stock:lock: skuId; RLock lock redissonClient.getLock(lockKey); // 方式一自动续期推荐 lock.lock(); try { // 1. 查询当前库存 Integer stock getStockFromDB(skuId); if (stock null || stock quantity) { return false; // 库存不足 } // 2. 扣减库存数据库操作 int affected updateStock(skuId, stock - quantity); return affected 0; } finally { lock.unlock(); } } } 要点解析锁 key 用stock:lock:skuId—— 按 SKU 粒度锁不同 SKU 不互相影响锁 事务是先锁后事务防止第一个线程释放锁后第二个线程读到旧数据看门狗保证业务就算慢也不会锁过期✅ 一句话总结RLock 按业务粒度锁 先锁后事务 分布式环境下的线程安全5.2 案例双 11 接口限流RateLimiter 需求描述某秒杀接口单机最多每 5 秒处理 100 个请求超出直接返回「拥挤」。 实现代码RestController public class SeckillController { Autowired private RedissonClient redissonClient; GetMapping(/seckill/{skuId}) public Result seckill(PathVariable Long skuId) { RRateLimiter rateLimiter redissonClient.getRateLimiter(rate:seckill: skuId); // 每个 SKU 每 5 秒最多 100 个许可 rateLimiter.trySetRate(RateType.OVERALL, 100, 5, RateIntervalUnit.SECONDS); if (!rateLimiter.tryAcquire(1)) { return Result.fail(系统拥挤请稍后再试); } // 放行——进入秒杀逻辑 return seckillService.doSeckill(skuId); } } 输出结果峰值 10 万 QPS接口正常响应超出部分秒拒下游数据库无压力。 要点解析RateType.OVERALL所有服务实例共享限流额度tryAcquire非阻塞返回 false 直接拒绝比acquire阻塞更合理限流要在最外层做不要等到业务逻辑里再限5.3 案例延迟队列实现订单超时自动取消 需求描述下单后 30 分钟未支付自动取消订单恢复库存。 实现代码Component public class OrderTimeoutService { Autowired private RedissonClient redissonClient; private RBlockingQueueString blockingQueue; private RDelayedQueueString delayedQueue; PostConstruct public void init() { blockingQueue redissonClient.getBlockingQueue(order:timeout:queue); delayedQueue redissonClient.getDelayedQueue(blockingQueue); // 启动消费者线程 new Thread(this::consume, order-timeout-consumer).start(); } /** * 下单时注册超时任务 */ public void registerTimeout(Long orderId) { String orderKey order: orderId; delayedQueue.offer(orderKey, 30, TimeUnit.MINUTES); } /** * 消费者持续监听延迟队列 */ private void consume() { while (true) { try { String orderKey blockingQueue.take(); // 阻塞等待 Long orderId Long.parseLong(orderKey.split(:)[1]); // 检查订单是否已支付 Order order orderService.getById(orderId); if (order ! null order.getStatus() 0) { // 待支付 orderService.cancelOrder(orderId); // 取消订单 stockService.restoreStock(order.getSkuId(), order.getQuantity()); // 恢复库存 log.info(订单超时取消: {}, orderId); } } catch (Exception e) { log.error(取消订单异常, e); } } } } 要点解析RDelayedQueue内部把延迟任务按到期时间排序到期后自动转入blockingQueue消费者用take()阻塞比轮询优雅得多生产环境下可以用 Async 或者线程池替代new Thread5.4 案例分布式读写锁 本地缓存解决缓存击穿 需求描述热点配置数据读多写少要求所有节点读到最新配置且写入时不会引起缓存击穿。 实现代码Component public class ConfigService { Autowired private RedissonClient redissonClient; private final MapString, String localCache new ConcurrentHashMap(); public String getConfig(String key) { RReadWriteLock rwLock redissonClient.getReadWriteLock(config:rw: key); // 先查本地缓存 String value localCache.get(key); if (value ! null) return value; // 读锁——多个节点可以并发读 rwLock.readLock().lock(); try { // 双重检查 value localCache.get(key); if (value ! null) return value; // 从 Redis 加载到本地缓存 RBucketString bucket redissonClient.getBucket(config: key); value bucket.get(); if (value ! null) { localCache.put(key, value); } return value; } finally { rwLock.readLock().unlock(); } } public void updateConfig(String key, String newValue) { RReadWriteLock rwLock redissonClient.getReadWriteLock(config:rw: key); // 写锁——互斥等待所有读锁释放 rwLock.writeLock().lock(); try { // 更新 Redis RBucketString bucket redissonClient.getBucket(config: key); bucket.set(newValue); // 清空本地缓存下次读时重新加载 localCache.remove(key); } finally { rwLock.writeLock().unlock(); } } } 要点解析读多写少用读写锁比 RLock 的独占锁性能好很多本地缓存 Redis 双层读性能极好写时清空本地缓存 写锁保证所有节点看到最新值六、常见坑与最佳实践6.1 易错点清单#坑点现象原因✅ 避坑方案1锁未释放死锁所有线程卡住业务异常时 finally 没 unlock用try { ... } finally { lock.unlock() }模板2解锁失败抛异常无影响但日志报警没获取锁就 unlock只在tryLock返回 true 后才解锁3看门狗与手动超时冲突续期失效手动指定了 leaseTime 时看门狗不启动想续期就不要传 leaseTime想固定超时就显式设置4锁粒度太粗性能大幅下降用了全局锁 key一把锁锁全表按业务粒度设计 key业务:资源:id5锁粒度太细死锁、脏读两个方法分别锁 A 和 B交叉调用统一锁顺序或用更粗的粒度6RMapCache 不生效缓存不过期没配置过期的模式put(key, v, ttl, unit)必须传 ttl 参数7Redisson 版本与 Redis 版本不匹配连接失败、命令异常EOL 的 Redis 版本不支持新命令看 Redisson 兼容矩阵6.2 异常处理模板RLock lock redissonClient.getLock(business:lock: bizId); boolean locked false; try { // 尝试获取锁最多等 3 秒持有锁不超过 10 秒 locked lock.tryLock(3, 10, TimeUnit.SECONDS); if (!locked) { throw new BusinessException(系统繁忙请稍后再试); } // 业务逻辑 doBusiness(); } catch (BusinessException e) { throw e; // 业务异常直接抛交给上层处理 } catch (Exception e) { log.error(执行业务失败, bizId{}, bizId, e); throw new BusinessException(系统异常); } finally { if (locked) { try { lock.unlock(); } catch (Exception e) { log.error(解锁异常, bizId{}, bizId, e); } } }6.3 最佳实践清单✅锁粒度按业务资源设计 key。order:lock:123优于order:lock:all✅优先用lock()看门狗而不是手动设超时。除非你明确知道业务最多跑多久✅先锁后事务。Spring 的Transactional在方法结束时提交锁释放一般在事务提交之后才执行✅限流放在最外层。像 Gateway 或 Filter 层不要等到 Controller 里再限✅延迟队列替代轮询。需要定时检查状态的用RDelayedQueue代替Scheduled轮询✅使用 tryLock 而不是 lock。lock()永久阻塞tryLock(waitTime)有时限体验更好❌避免锁 key 用 UUID / 随机值。同一把锁应该用相同 key 才能互斥❌避免获取锁后长时间阻塞如 RPC 调用。业务里面再嵌套远程调用看门狗续期也撑不住七、总结与学习路线图7.1 知识点提炼核心口诀锁用 RLock粒度按业务定 看门狗保命finally 要记得清 限流 RateLimiter放在最外层 延迟队列 RDelayed替代轮询省心力 读写锁 RWLock读多写少首选它核心要点速览维度要点一句话记住锁RLock 可重入 看门狗自动续期别担心业务跑不完限流RRateLimiter漏桶算法全局/按客户端限队列RDelayedQueue延迟30分钟自动入阻塞队列缓存RMapCache RLocalCachedMap多级缓存一致性靠读写锁对比Redisson vs 手写Redisson 少写80% 坑代码自检清单我能说清楚看门狗机制的工作时机和原理我能写出 RLock 的标准用法模板tryLock finally unlock我知道什么场景用 RLock什么场景用 RReadWriteLock我能用 RRateLimiter 实现接口级别的分布式限流我能用 RDelayedQueue 替代定时轮询做订单超时取消我知道锁粒度太粗和太细分别有什么问题我能在不查资料的情况下写出一个生产可用的分布式锁代码7.2 反思与后续规划本次总结学会了 Redisson 最常用的 8 个组件覆盖了分布式锁、限流、队列、缓存四大场景理解了看门狗机制解决了手写 Redis 锁的最大痛点掌握了「锁要分粒度、tryLock 优先、finally 必解锁」等核心原则下一步学习路线图阶段一基础 — 本篇已覆盖RLock / RReadWriteLock / RRateLimiter / RQueue / RTopic ↓ 阶段二进阶RExecutorService 分布式执行器 RRemoteService 远程调用 ↓ 阶段三源码Redisson 的 Lua 脚本如何保证原子性看门狗线程池怎么管理的 ↓ 阶段四实战与 Spring Cache 集成、与 Sentinel 结合做熔断限流、多级缓存架构实战推荐延伸阅读Redisson 官方 Wiki — 最权威的 API 参考文档每个接口都有示例Redisson 看门狗源码分析 — 深入了解自动续期的实现细节Spring Boot Redisson 最佳实践 — 生产环境配置和性能调优建议