当前位置: 首页 > news >正文

从零理解 Redisson:Java 分布式工具箱的入门与实战

从零理解 RedissonJava 分布式工具箱的入门与实战一、Redisson 是什么1.1 一句话定义Redisson 是一个基于 Redis 的 Java 客户端框架它把 Redis 的底层命令封装成了 Java 开发者熟悉的数据结构和工具锁、队列、Map、信号量等让你像使用本地 Java 对象一样使用分布式功能。1.2 类比理解你熟悉的Redisson 提供的区别java.util.HashMapRMap分布式Map数据存在 Redis多个服务实例共享java.util.concurrent.locks.ReentrantLockRLock分布式锁锁存在 Redis跨JVM生效java.util.concurrent.BlockingQueueRBlockingQueue分布式队列队列存在 Redis多实例消费java.util.concurrent.SemaphoreRSemaphore分布式信号量信号量存在 Redis跨实例限流简单说Redisson Redis Java 并发工具包的分布式版本。1.3 Redisson vs Jedis vs Lettuce框架定位特点JedisRedis 底层客户端直接发送 Redis 命令简单轻量LettuceRedis 底层客户端基于 Netty支持异步Spring Boot 默认RedissonRedis 高级客户端封装了分布式锁、集合、队列等高级功能// Jedis直接操作 Redis 命令jedis.set(key,value);jedis.setnx(lock-key,holder);// Lettuce通过 Spring RedisTemplate也是操作命令redisTemplate.opsForValue().set(key,value);redisTemplate.opsForValue().setIfAbsent(lock-key,holder);// Redisson面向对象的方式屏蔽底层命令RLocklockredissonClient.getLock(lock-key);lock.lock();// 内部自动处理 SETNX、过期时间、看门狗等二、为什么需要 Redisson2.1 自己实现分布式锁的痛点如果用 Jedis/Lettuce 自己实现分布式锁需要处理// 自己实现代码量大容易出错publicbooleantryLock(Stringkey,StringholderId,longtimeout){// 1. 加锁SETNX 过期时间必须原子操作BooleansuccessredisTemplate.opsForValue().setIfAbsent(key,holderId,timeout,TimeUnit.SECONDS);returnBoolean.TRUE.equals(success);}publicvoidunlock(Stringkey,StringholderId){// 2. 释放锁必须验证持有者必须用 Lua 脚本保证原子性Stringscriptif redis.call(get,KEYS[1]) ARGV[1] then return redis.call(del,KEYS[1]) else return 0 end;redisTemplate.execute(newDefaultRedisScript(script,Long.class),Collections.singletonList(key),holderId);}// 3. 还需要自己实现// - 看门狗续期// - 可重入支持// - 公平锁// - 红锁RedLock// - 异步加锁// - 锁的监听和通知2.2 Redisson 帮你做了什么// Redisson一行代码搞定内部自动处理所有细节RLocklockredissonClient.getLock(my-lock);lock.lock();try{// 业务逻辑}finally{lock.unlock();}Redisson 内部自动处理了加锁的原子性Lua 脚本释放锁的持有者验证看门狗自动续期可重入计数等待队列和公平性集群/哨兵模式的兼容注博客https://blog.csdn.net/badao_liumang_qizhi三、快速上手3.1 引入依赖!-- Maven --dependencygroupIdorg.redisson/groupIdartifactIdredisson-spring-boot-starter/artifactIdversion3.27.0/version/dependency3.2 配置连接# application.ymlspring:redis:host:127.0.0.1port:6379password:your-password或者使用 Redisson 自己的配置# redisson.ymlsingleServerConfig:address:redis://127.0.0.1:6379password:your-passwordconnectionMinimumIdleSize:5connectionPoolSize:103.3 注入使用ServicepublicclassOrderServiceImplimplementsOrderService{ResourceprivateRedissonClientredissonClient;publicvoidprocessOrder(IntegerorderId){// 获取锁对象此时还没有加锁RLocklockredissonClient.getLock(order-orderId);try{// 加锁等待10秒锁自动30秒过期booleanacquiredlock.tryLock(10,30,TimeUnit.SECONDS);if(!acquired){thrownewRuntimeException(获取锁失败);}// 执行业务doProcess(orderId);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}finally{// 释放锁if(lock.isHeldByCurrentThread()){lock.unlock();}}}}四、Redisson 核心功能详解4.1 分布式锁RLock这是 Redisson 最常用的功能。RLocklockredissonClient.getLock(my-lock);// 方式一阻塞加锁一直等到获取成功lock.lock();// 方式二尝试加锁等待指定时间booleansuccesslock.tryLock(10,TimeUnit.SECONDS);// 方式三尝试加锁 指定锁过期时间booleansuccesslock.tryLock(10,30,TimeUnit.SECONDS);// 参数1最多等10秒// 参数2锁30秒后自动释放不启用看门狗// 方式四尝试加锁 看门狗自动续期booleansuccesslock.tryLock(10,TimeUnit.SECONDS);// 不指定第二个参数 → 启用看门狗锁不会自动过期// 释放锁lock.unlock();4.2 公平锁RFairLock普通锁是谁抢到算谁的公平锁是先来先得。// 公平锁按请求顺序获取锁RLockfairLockredissonClient.getFairLock(fair-lock);fairLock.lock();try{// 业务逻辑}finally{fairLock.unlock();}4.3 读写锁RReadWriteLock允许多个线程同时读但写的时候独占。RReadWriteLockrwLockredissonClient.getReadWriteLock(rw-lock);// 读锁多个线程可以同时持有RLockreadLockrwLock.readLock();readLock.lock();try{// 读取数据多个线程可以同时读returndataRepository.findById(id);}finally{readLock.unlock();}// 写锁独占其他读和写都要等待RLockwriteLockrwLock.writeLock();writeLock.lock();try{// 修改数据独占dataRepository.save(data);}finally{writeLock.unlock();}4.4 分布式MapRMap// 像使用 HashMap 一样但数据存在 RedisRMapString,UserInfouserCacheredissonClient.getMap(user-cache);// 存入userCache.put(user-123,userInfo);// 读取UserInfoinfouserCache.get(user-123);// 设置过期时间userCache.put(user-123,userInfo,30,TimeUnit.MINUTES);4.5 分布式队列RBlockingQueue// 生产者RBlockingQueueStringqueueredissonClient.getBlockingQueue(task-queue);queue.offer(task-001);// 消费者阻塞等待Stringtaskqueue.take();// 如果队列为空会阻塞等待processTask(task);4.6 限流器RRateLimiter// 创建限流器每秒最多10个请求RRateLimiterlimiterredissonClient.getRateLimiter(api-limiter);limiter.trySetRate(RateType.OVERALL,10,1,RateIntervalUnit.SECONDS);// 使用if(limiter.tryAcquire()){// 允许通过processRequest();}else{// 被限流thrownewRuntimeException(请求过于频繁);}五、RLock 的内部原理5.1 加锁过程Redisson 加锁时执行的 Lua 脚本简化版-- 如果锁不存在ifredis.call(exists,KEYS[1])0then-- 创建锁设置持有者和重入计数redis.call(hset,KEYS[1],ARGV[2],1)-- 设置过期时间redis.call(pexpire,KEYS[1],ARGV[1])returnnilend-- 如果锁存在且是自己持有的可重入ifredis.call(hexists,KEYS[1],ARGV[2])1then-- 重入计数1redis.call(hincrby,KEYS[1],ARGV[2],1)-- 重置过期时间redis.call(pexpire,KEYS[1],ARGV[1])returnnilend-- 锁被别人持有返回剩余过期时间returnredis.call(pttl,KEYS[1])5.2 Redis 中锁的数据结构Key: my-lock Type: Hash Value: holder-id-thread-1 → 2 (重入计数2表示加了2次锁) TTL: 30000ms5.3 释放锁过程-- 检查锁是否是自己持有的ifredis.call(hexists,KEYS[1],ARGV[1])0thenreturnnil-- 不是自己的锁不操作end-- 重入计数-1localcounterredis.call(hincrby,KEYS[1],ARGV[1],-1)ifcounter0then-- 还有重入只重置过期时间redis.call(pexpire,KEYS[1],ARGV[2])return0else-- 计数归零真正释放锁redis.call(del,KEYS[1])-- 通知等待的线程redis.call(publish,KEYS[2],ARGV[3])return1end六、Redisson 与 Spring Boot 集成6.1 自动配置最简方式引入redisson-spring-boot-starter后Redisson 会自动读取spring.redis配置创建RedissonClient。ServicepublicclassMyService{ResourceprivateRedissonClientredissonClient;// 自动注入publicvoiddoSomething(){RLocklockredissonClient.getLock(key);// ...}}6.2 手动配置需要自定义参数时ConfigurationpublicclassRedissonConfig{BeanpublicRedissonClientredissonClient(){ConfigconfignewConfig();config.useSingleServer().setAddress(redis://127.0.0.1:6379).setPassword(password).setConnectionMinimumIdleSize(5).setConnectionPoolSize(20).setTimeout(3000).setRetryAttempts(3);returnRedisson.create(config);}}6.3 集群模式配置BeanpublicRedissonClientredissonClient(){ConfigconfignewConfig();config.useClusterServers().addNodeAddress(redis://node1:6379,redis://node2:6379,redis://node3:6379).setPassword(password);returnRedisson.create(config);}七、实战示例商品库存扣减7.1 完整代码/** * 库存服务实现. */ServicepublicclassStockServiceImplimplementsStockService{ResourceprivateRedissonClientredissonClient;ResourceprivateStockRepositorystockRepository;/** * 扣减库存使用分布式锁防止超卖. * * param skuId 商品SKU ID * param quantity 扣减数量 * return true扣减成功false库存不足 */Transactional(rollbackForException.class)publicbooleandeductStock(IntegerskuId,Integerquantity){// 按SKU维度加锁StringlockKeystock-deduct-skuId;RLocklockredissonClient.getLock(lockKey);try{// 等待5秒不指定leaseTime启用看门狗booleanacquiredlock.tryLock(5,TimeUnit.SECONDS);if(!acquired){log.warn(获取库存锁超时, skuId:{},skuId);returnfalse;}// 查询当前库存StockstockstockRepository.findBySkuId(skuId);if(stocknull||stock.getQuantity()quantity){log.info(库存不足, skuId:{}, 当前:{}, 需要:{},skuId,stocknull?0:stock.getQuantity(),quantity);returnfalse;}// 扣减库存stock.setQuantity(stock.getQuantity()-quantity);stockRepository.save(stock);log.info(库存扣减成功, skuId:{}, 扣减:{}, 剩余:{},skuId,quantity,stock.getQuantity());returntrue;}catch(InterruptedExceptione){Thread.currentThread().interrupt();log.warn(获取库存锁被中断, skuId:{},skuId);returnfalse;}finally{// 释放锁if(lock.isHeldByCurrentThread()){lock.unlock();}}}}7.2 关键代码解读// 1. getLock(key) — 获取锁对象还没加锁RLocklockredissonClient.getLock(lockKey);// 2. tryLock(waitTime) — 尝试加锁// - 如果锁空闲立即获取返回 true// - 如果锁被占用等待最多5秒// - 5秒内锁释放了获取成功返回 true// - 5秒后仍被占用放弃返回 falsebooleanacquiredlock.tryLock(5,TimeUnit.SECONDS);// 3. isHeldByCurrentThread() — 检查当前线程是否持有锁// 防止释放别人的锁if(lock.isHeldByCurrentThread()){lock.unlock();}八、Redisson 功能全景图RedissonClient │ ├── 分布式锁 │ ├── RLock可重入锁 │ ├── RFairLock公平锁 │ ├── RReadWriteLock读写锁 │ ├── RSemaphore信号量 │ └── RCountDownLatch倒计时门闩 │ ├── 分布式集合 │ ├── RMap分布式Map │ ├── RSet分布式Set │ ├── RList分布式List │ ├── RSortedSet有序集合 │ └── RQueue / RBlockingQueue队列 │ ├── 分布式服务 │ ├── RRemoteService远程调用 │ ├── RScheduledExecutorService定时任务 │ └── RExecutorService分布式执行器 │ └── 其他工具 ├── RRateLimiter限流器 ├── RAtomicLong原子计数器 ├── RTopic发布订阅 └── RBloomFilter布隆过滤器九、常见问题Q1Redisson 和 Spring Cache 能一起用吗可以。Redisson 提供了 Spring Cache 的实现Cacheable(cacheNamesuserCache,key#userId)publicUserInfogetUserById(IntegeruserId){returnuserRepository.findById(userId).orElse(null);}Q2Redisson 支持 Redis 集群吗支持。Redisson 支持单机、哨兵、集群、主从等所有 Redis 部署模式。Q3Redisson 的性能如何加锁/释放锁通常 1-3 毫秒取决于网络延迟比自己用 RedisTemplate 实现稍慢多了一些内部逻辑但比 ZooKeeper 实现快很多Q4项目中已经有 RedisTemplate 了还需要 Redisson 吗两者可以共存。RedisTemplate 用于简单的缓存读写Redisson 用于分布式锁、限流等高级功能。十、总结问题答案Redisson 是什么基于 Redis 的 Java 分布式工具框架和 Jedis/Lettuce 的区别Jedis/Lettuce 是底层客户端Redisson 是高级封装最常用的功能分布式锁RLock为什么不自己实现分布式锁自己实现需要处理原子性、续期、可重入、持有者验证等细节如何引入加redisson-spring-boot-starter依赖即可性能影响加锁/释放锁约 1-3ms对大多数业务可忽略
http://www.zskr.cn/news/1383900.html

相关文章:

  • 探析数字孪生的核心特性与应用价值
  • 告别AWCC臃肿:AlienFX Tools终极轻量级控制方案深度评测
  • 谈美---朱光潜前20页
  • 脉冲神经网络加速器设计与边缘计算优化
  • OpenIPC开源固件:5分钟解锁网络摄像头的终极控制权
  • 告别全屏截图!用Playwright精准捕获页面元素,让你的测试报告更专业
  • 告别MQTT.fx!用STM32+ESP8266直连新版OneNET,手把手教你从零配置JSON数据上传
  • 独家专访杨元庆:详解联想集团千亿美金营收目标
  • Redis三大缓存异常问题
  • Ubuntu经常安装软件
  • 航空发动机叶片三维扫描-诺斯顿
  • 创业团队如何利用Taotoken实现低成本多模型AI能力快速验证
  • 半监督学习在肺部疾病声音分类中的应用:MFCC+CNN与三模块协同训练
  • 5分钟学会BlenderKit:让你在Blender里拥有一个永不枯竭的创意资源库
  • 小白友好:OpenClaw Windows 一键部署教程(含安装包)
  • LVGL多页面开发避坑:用内部Timer替代轮询,解决页面切换时的内存踩踏问题
  • 用Azure Kinect DK和Body Tracking SDK,5分钟实现一个实时人体骨骼点检测Demo(C++版)
  • 电磁流量计十大品牌排名 - 水质仪表品牌排行榜
  • 【常规维护】Claude Code v2.1.150 发布:聚焦内部基础设施演进
  • 榨干Codex!OpenAI工程师亲授Codex真正用法
  • 真可用!美团数字人模型开源,MV、电商等统统拿下
  • 2026年5月西安AI搜索流量怎么抢?优质GEO优化服务商TOP5榜单 - 资讯快报
  • FortiGate DNS服务器:不只是域名解析,更是安全策略第一道防线
  • 私有化视频会议系统EasyDSS一个平台,搞定直播、点播、作业、统计—学校终于不用买多套系统了
  • 临沂黄金回收优选榜单|甄选特色门店 合规经营无套路 铸就本地行业标杆 - 鑫顺黄金回收
  • 如何快速解锁中兴光猫权限:zteOnu工具完整使用指南
  • 百度深度学习研究院的“叛将“,带着一颗芯片改变了中国智能驾驶——地平线余凯,从ImageNet冠军到征程出货1000万
  • Harness终极实战:打造全链路可观测性Agent环境
  • Linux命令总结
  • LayaAir引擎新增华为小游戏发布能力并支持WebGPU渲染模式