使用 Redisson 实现分布式锁—解决方案详解
Redisson 是 Redis 官方推荐的 Java 客户端,提供了一系列分布式服务实现,其中分布式锁是其核心功能之一。本文将深入解析 Redisson 分布式锁的实现原理、高级特性和最佳实践。
一、Redisson 分布式锁的优势
与传统实现的对比
特性 | 手动实现 | Redisson 实现 |
---|---|---|
锁续期 | 需手动实现看门狗 | 内置自动续期机制 |
可重入性 | 不支持 | 原生支持可重入锁 |
锁类型 | 基础锁 | 公平锁/联锁/读写锁/红锁 |
等待机制 | 自旋或阻塞 | 订阅发布机制 |
异常处理 | 手动处理 | 完善的异常处理链 |
集群支持 | 需自行处理故障转移 | 原生支持Redis集群模式 |
二、核心实现原理
1. 加锁原子性保证
Redisson 使用 Lua 脚本保证原子操作:
if (redis.call('exists', KEYS[1]) == 0)
then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1)
then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil;
end;
return redis.call('pttl', KEYS[1]);
2. 看门狗锁续期机制
private void scheduleExpirationRenewal(long threadId) {// 每10秒续期一次Timeout task = commandExecutor.getConnectionManager().newTimeout(timeout -> {// 续期逻辑RFuture<Boolean> future = renewExpirationAsync(threadId);future.onComplete((res, e) -> {if (e != null) {// 异常处理return;}if (res) {// 递归调用实现循环续期scheduleExpirationRenewal(threadId);}});}, lockWatchdogTimeout / 3, TimeUnit.MILLISECONDS);
}
三、完整使用示例
1. 添加 Maven 依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.27.0</version>
</dependency>
2. 配置 Redisson 客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("your_password").setDatabase(0).setConnectionPoolSize(64).setConnectionMinimumIdleSize(24);RedissonClient redisson = Redisson.create(config);
3. 基础锁使用
RLock lock = redisson.getLock("orderLock");void processOrder(String orderId) {try {// 尝试获取锁,等待100秒,锁自动释放时间30秒if (lock.tryLock(100, 30, TimeUnit.SECONDS)) {// 关键业务逻辑Order order = orderService.getOrder(orderId);order.process();orderService.update(order);}} catch (InterruptedException e) {Thread.currentThread().interrupt();log.error("锁获取被中断", e);} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();log.info("订单{}处理完成,锁已释放", orderId);}}
}
四、高级锁特性详解
1. 可重入锁(Reentrant Lock)
public void nestedLockExample() {RLock lock = redisson.getLock("reentrantLock");lock.lock();try {// 外层业务逻辑innerMethod(lock);} finally {lock.unlock();}
}private void innerMethod(RLock lock) {// 内层方法再次获取锁lock.lock(); // 计数+1try {// 内层业务逻辑} finally {lock.unlock(); // 计数-1}
}
2. 公平锁(Fair Lock)
RLock fairLock = redisson.getFairLock("fairLock");
fairLock.lock();
try {// 按照请求顺序获取锁资源executeCriticalSection();
} finally {fairLock.unlock();
}
3. 读写锁(ReadWrite Lock)
RReadWriteLock rwLock = redisson.getReadWriteLock("resourceLock");// 读操作
void readData() {RLock readLock = rwLock.readLock();readLock.lock();try {// 多个线程可并发读取return fetchDataFromDB();} finally {readLock.unlock();}
}// 写操作
void writeData(Object data) {RLock writeLock = rwLock.writeLock();writeLock.lock();try {// 独占写权限updateDataInDB(data);} finally {writeLock.unlock();}
}
4. 联锁(MultiLock)
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");// 同时获取多个锁
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2, lock3);
multiLock.lock();
try {// 操作多个资源updateResource1();updateResource2();
} finally {multiLock.unlock();
}
五、红锁(RedLock)实现
解决Redis集群脑裂问题
Config config1 = createConfig("redis://node1:6379");
Config config2 = createConfig("redis://node2:6379");
Config config3 = createConfig("redis://node3:6379");RedissonClient client1 = Redisson.create(config1);
RedissonClient client2 = Redisson.create(config2);
RedissonClient client3 = Redisson.create(config3);RLock lock1 = client1.getLock("globalLock");
RLock lock2 = client2.getLock("globalLock");
RLock lock3 = client3.getLock("globalLock");// 构建红锁
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {// 尝试获取锁,锁定时间60秒if (redLock.tryLock(100, 60, TimeUnit.SECONDS)) {// 关键业务逻辑processGlobalResource();}
} finally {redLock.unlock();// 关闭客户端连接Stream.of(client1, client2, client3).forEach(RedissonClient::shutdown);
}
六、生产环境最佳实践
1. 锁命名规范
// 业务域:资源类型:资源ID
String lockKey = "order:processing:" + orderId;
RLock lock = redisson.getLock(lockKey);
2. 合理配置参数
config.setLockWatchdogTimeout(30_000); // 看门狗超时时间
config.setNettyThreads(32); // 网络线程数// 锁配置
RedissonFairLock lock = (RedissonFairLock) redisson.getFairLock("lock");
lock.setLockWatchdogTimeout(60_000); // 覆盖全局配置
3. 异常处理策略
try {if (lock.tryLock(10, 30, SECONDS)) {// 业务逻辑}
} catch (RedisResponseTimeoutException e) {// Redis响应超时处理metrics.recordTimeout();throw new ServiceUnavailableException("Redis超时");
} catch (RedisConnectionException e) {// 连接异常处理fallbackProcessor.process();
} catch (Exception e) {// 通用异常处理log.error("锁操作异常", e);
} finally {unlockSafely(lock);
}void unlockSafely(RLock lock) {try {if (lock.isHeldByCurrentThread() && lock.isLocked()) {lock.unlock();}} catch (IllegalMonitorStateException ex) {// 锁状态异常处理}
}
4. 监控与告警
// 监控锁等待时间
long start = System.currentTimeMillis();
if (lock.tryLock(waitTime, leaseTime, unit)) {long elapsed = System.currentTimeMillis() - start;metrics.recordLockWaitTime(elapsed);// ...
}// 监控锁持有时间
LockHoldTimer timer = metrics.startLockHoldTimer();
try {// 业务逻辑
} finally {timer.stop();
}// JMX监控
Redisson redisson = (Redisson) redissonClient;
redisson.getRemoteService().registerService(LockMetrics.class, lockMetrics);
七、故障场景处理方案
1. 客户端宕机处理
2. 网络分区处理
// 使用红锁提高可用性
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.lock(10, TimeUnit.SECONDS); // 设置较短租期// 添加监听器处理连接丢失
lock.addListener(new LockListener() {@Overridepublic void onLockLost() {// 触发补偿机制compensationService.compensate();}
});
八、性能优化策略
1. 锁粒度优化
// 粗粒度锁(不推荐)
RLock coarseLock = redisson.getLock("orderProcessing");// 细粒度锁(推荐)
RLock fineGrainedLock = redisson.getLock("order:" + orderId);
2. 锁分离技术
// 读多写少场景
RReadWriteLock rwLock = redisson.getReadWriteLock("resource");
rwLock.readLock().lock(); // 读操作
rwLock.writeLock().lock(); // 写操作// 热点数据场景
long shardId = orderId % 16;
RLock shardedLock = redisson.getLock("order_lock:" + shardId);
3. 异步锁操作
// 异步获取锁
RFuture<Boolean> lockFuture = lock.tryLockAsync(10, 30, TimeUnit.SECONDS);lockFuture.onComplete((res, ex) -> {if (res) {// 获取锁成功processAsync();} else {// 获取锁失败fallback();}
});// 异步释放锁
lock.unlockAsync();
九、常见问题解决方案
1. 锁等待超时
场景:系统负载高时锁获取超时
解决方案:
// 指数退避策略
long baseDelay = 50;
long maxDelay = 1000;
Random random = new Random();while (!lock.tryLock()) {long delay = baseDelay + random.nextInt((int) baseDelay);Thread.sleep(delay);baseDelay = Math.min(baseDelay * 2, maxDelay);
}
2. 锁提前释放
场景:GC暂停导致看门狗续期失败
解决方案:
// 增加续期超时时间
config.setLockWatchdogTimeout(60_000);// 添加JVM参数减少GC暂停
-XX:+UseG1GC -XX:MaxGCPauseMillis=100
3. 锁状态不一致
场景:Redis故障转移后锁状态丢失
解决方案:
// 使用红锁
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);// 启用持久化
config.setLockWatchdogTimeout(0); // 禁用看门狗
lock.lock(30, TimeUnit.SECONDS); // 依赖Redis持久化
十、Redisson 与企业架构集成
Spring Boot 自动配置
@Configuration
public class RedissonConfig {@Bean(destroyMethod = "shutdown")public RedissonClient redisson(@Value("${redis.address}") String address) {Config config = new Config();config.useSingleServer().setAddress(address).setConnectionPoolSize(64);return Redisson.create(config);}@Beanpublic DistributedLockFactory lockFactory(RedissonClient redisson) {return new RedissonLockFactory(redisson);}
}@Service
public class OrderService {@Autowiredprivate DistributedLockFactory lockFactory;public void processOrder(String orderId) {Lock lock = lockFactory.getLock("order:" + orderId);if (lock.tryLock()) {try {// 业务逻辑} finally {lock.unlock();}}}
}
与 Spring Cloud 集成
# application.yml
spring:cloud:distributed-lock:enabled: trueprovider: redissonredisson:config-file: classpath:redisson.yaml
@SpringBootApplication
@EnableDistributedLock
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}@Service
public class InventoryService {@DistributedLock(lockKey = "'inventory:' + #skuId")public void reduceStock(String skuId, int quantity) {// 无需手动加锁inventoryDao.reduce(skuId, quantity);}
}
总结:Redisson 分布式锁最佳实践
-
锁选择策略:
- 普通场景:
RLock
基础锁 - 读多写少:
RReadWriteLock
读写锁 - 高可用要求:
RedissonRedLock
红锁 - 顺序执行:
RedissonFairLock
公平锁
- 普通场景:
-
关键配置参数:
# 看门狗续期时间(默认30秒) lockWatchdogTimeout=30000 # 锁等待时间(根据业务设置) waitTime=5000 # 锁租期时间(大于业务执行时间) leaseTime=30000
-
性能优化建议:
- 锁粒度最小化
- 读写锁分离
- 避免长时间持有锁
- 热点数据分片
-
容灾方案:
- 多数据中心部署
- 降级策略(本地锁/熔断)
- 事务补偿机制
最终建议:
- 生产环境使用 Redisson 3.24+ 版本
- 集群环境使用红锁(至少3个独立主节点)
- 结合 Prometheus + Grafana 监控锁指标
- 定期进行混沌工程测试
通过合理使用 Redisson 分布式锁,可以构建出高并发、高可靠的分布式系统。但需谨记:分布式锁是最后的选择而非首选方案,优先考虑无锁设计(如CAS)、事务隔离级别优化等方案能获得更好的系统性能。
相关文章:

使用 Redisson 实现分布式锁—解决方案详解
Redisson 是 Redis 官方推荐的 Java 客户端,提供了一系列分布式服务实现,其中分布式锁是其核心功能之一。本文将深入解析 Redisson 分布式锁的实现原理、高级特性和最佳实践。 一、Redisson 分布式锁的优势 与传统实现的对比 特性手动实现Redisson 实现…...

结合三维基因建模与智能体技术打造工业软件无码平台
通过深度整合 Protocol Buffers (Protobuf)、gRPC 及 Microsoft AI 技术,构建面向智能制造的高性能、智能化 PLM 平台。 一、Protocol Buffers 深度集成 1. 基因模型标准化定义 三维基因容器 Protobuf 规范: protobuf syntax "proto3"; pa…...

Python Day46
Task: 1.不同CNN层的特征图:不同通道的特征图 2.什么是注意力:注意力家族,类似于动物园,都是不同的模块,好不好试了才知道。 3.通道注意力:模型的定义和插入的位置 4.通道注意力后的特征图和热力…...

基于PostGIS的各地级市路网长度统计及Echarts图表可视化实践-以湖南省为例
目录 前言 一、路网长度计算 1、地级市列表查询 2、地级市路网长度查询 二、Echarts可视化实现 1、Echarts后端生成 2、引入Colormap配色 3、前端微调 三、总结 前言 在当今快速发展的社会中,交通路网的建设与布局对于一个地区的经济发展、居民生活以及城市…...

mac版excel如何制作时长版环形图
设置辅助列 创建簇状柱形图 将辅助列绘制在次坐标轴 工作时长在主坐标轴,右键分别更改图表类型为圆环。 辅助列圆环全部为灰色,边框为白色 辅助列设置透明度100% 设置辅助列和工作时长列同样的圆环大小 可得 核心:只要辅助列边框不透明…...
PCB设计教程【大师篇】——STM32开发板原理图设计(电源部分)
前言 本教程基于B站Expert电子实验室的PCB设计教学的整理,为个人学习记录,旨在帮助PCB设计新手入门。所有内容仅作学习交流使用,无任何商业目的。若涉及侵权,请随时联系,将会立即处理 目录 前言 1. 工程创建与前期…...
k8s4部署
configMap configmap概述:数据会存储在etcd数据库,其应用场景主要在应用程序的配置 configmap支持的类型(1)键值对(2)多行数据 pod使用configmap资源有两种常见的方式(1)变量注入&a…...
贝叶斯医学分析中“先验”的如何进行选择(文献解读)
贝叶斯医学分析中“先验”的如何进行选择(文献解读) 作者:Callum Taylor, Kathryn Puxty, Tara Quasim, Martin Shaw 文章标题:Understanding Bayesian analysis of clinical trials: an overview for clinicians 期刊名称&#x…...
【汇编逆向系列】七、函数调用包含多个参数之浮点型- XMM0-3寄存器
目录 1. 汇编代码 1.1 debug编译 1.2 release编译 2. 汇编分析 2.1 浮点参数传递规则 2.2 栈帧rsp的变化时序 2.3 参数的访问逻辑 2.4 返回值XMM0寄存器 3. 汇编转化 3.1 Debug编译 3.2 Release 编译 3.3 C语言转化 1. 汇编代码 上一节介绍了整型的函数传参&#x…...

【MySQL系列】MySQL 执行 SQL 文件
博客目录 一、MySQL 执行 SQL 文件的常见场景二、MySQL 执行 SQL 文件的主要方法1. 使用 MySQL 命令行客户端2. 在 MySQL 交互界面中使用 source 命令3. 使用 MySQL Workbench 等图形化工具4. 使用编程语言接口 三、执行 SQL 文件时的注意事项1. 字符集问题2. 事务处理3. 错误处…...

论文MR-SVD
每个像素 7 个 FLOPs意思: FLOPs(浮点运算次数):衡量算法计算复杂度的指标,数值越小表示运算越高效。含义:对图像中每个像素进行处理时,仅需执行7 次浮点运算(如加减乘除等…...

Java 日期时间类全面解析
Java 日期时间类全面解析:从传统到现代的演进 一、发展历程概览 二、传统日期类(Java 8前) 1. java.util.Date - 日期表示类 Date now new Date(); // 当前日期时间 System.out.println(now); // Wed May 15 09:30:45 CST 2023// 特定时间…...

【工具-Wireshark 抓包工具】
工具-Wireshark 抓包工具 ■ Wireshark 抓包工具■ 通过IP指定查看■■ ■ Wireshark 抓包工具 抓包工具】win 10 / win 11:WireShark 下载、安装、使用 Wireshark下载 阿里云镜像 ■ 通过IP指定查看 ■ ■...
Linux安全机制:从SELinux到Intel SGX的堡垒
Linux安全机制:从SELinux到Intel SGX的堡垒 数字世界的钢铁长城 引言:操作系统的"防御工事" 当服务器每天承受数百万次攻击尝试时,Linux内核的安全机制如同精密的防御系统,在纳秒级时间内做出响应。现代Linux安全架构已…...

设备驱动与文件系统:06 目录与文件
磁盘使用的最后一层抽象:文件系统 今天我们讲第31讲,这一讲将完成磁盘对磁盘使用的最后一层抽象。对此板使用最后一层抽象,抽象出来的是什么呢? 实际上我们使用过磁盘,大家应该有这样的认识,最后不管这个磁…...
C++11 Token Bucket (令牌桶)算法的锁无实现及应用
Token Bucket(令牌桶)算法是一种在流量控制和资源分配领域被广泛应用的技术。它通过约束数据传输速率或任务执行频率,确保系统在资源有限的情况下,能够稳定、高效地运行,避免因突发流量或任务积压而导致的性能下降甚至…...
详细介绍uni-app中Composition API和Options API的使用方法
uni-app 中 Composition API 和 Options API 的使用方法详解 一、Options API(Vue 2.x 传统方式) 1. 基本结构 Options API 通过配置对象的不同选项(如 data、methods、computed 等)组织代码: <template><…...
delphi7 链表 使用方法
在 Delphi 中,链表是一种常见的数据结构,用于存储一系列的元素,其中每个元素都包含一个指向列表中下一个元素的引用。在 Delphi 7 中,你可以手动实现链表,或者使用一些现有的集合类,例如 TList 或者 TLinke…...

Linux 系统中的算法技巧与性能优化
引言 Linux 系统以其开源、稳定和高度可定制的特性,在服务器端、嵌入式设备以及开发环境中得到了极为广泛的应用。对于开发者而言,不仅要掌握在 Linux 环境下实现各类算法的方法,更要知晓如何利用系统特性对算法进行优化,以提升…...

【C++系列】模板类型特例化
1. C模板类型特例化介绍 定义:模板类型特例化(Template Specialization)是C中为模板的特定类型提供定制实现的机制,允许开发者对通用模板无法处理的特殊类型进行优化或特殊处理。 产生标准: C98/03…...

K8S认证|CKS题库+答案| 7. Dockerfile 检测
目录 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、修改 Dockerfile 3)、 修改 deployment.yaml 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 您必须在以…...
JAVA 对象 详解
对象 对象结构: 对象头(元数据和指向class的指针)、实例数据、对齐填充 数组对象: 对象头(元数据和指向class的指针)、数组长度、数组数据、对齐填充 对象创建: 一、当Java虚拟机遇到一条…...
MATLAB实战:四旋翼姿态控制仿真方案
以下是一个基于MATLAB/Simulink的四旋翼姿态控制仿真方案。本方案使用简化姿态动力学模型,并设计PID控制器进行稳定控制。 1. 四旋翼姿态动力学模型 核心方程:I * ω̇ ω (I * ω) τ 其中: I diag([Ixx, Iyy, Izz]) 为转动惯量矩阵 …...

基于Scala实现Flink的三种基本时间窗口操作
目录 代码结构 代码解析 (1) 主程序入口 (2) 窗口联结(Window Join) (3) 间隔联结(Interval Join) (4) 窗口同组联结(CoGroup) (5) 执行任务 代码优化 (1) 时间戳分配 (2) 窗口大小 (3) 输出格式…...

c++对halcon的动态链接库dll封装及调用(细细讲)
七个部分(是个大工程) 一,halcon封装函数导出cpp的内容介绍 二,c++中对halcon环境的配置 三,在配置环境下验证halcon代码 四,dll项目创建+环境配置 五,编辑dll及导出 六,调用打包好的动态链接库的配置 七,进行测试 一,halcon的封装及导出cpp的介绍 1,我这里…...

【优选算法】分治
一:颜色分类 class Solution { public:void sortColors(vector<int>& nums) {// 三指针法int n nums.size();int left -1, right n, i 0;while(i < right){if(nums[i] 0) swap(nums[left], nums[i]);else if(nums[i] 2) swap(nums[--right], num…...
QGraphicsView中鼠标点击与移动事件传递给MainWindow
在Qt图形应用程序开发中,QGraphicsView和QGraphicsScene框架提供了强大的2D图形显示功能。然而,当我们需要在主窗口(MainWindow)中处理这些视图中的鼠标事件。 问题背景 在典型的Qt图形应用程序架构中: MainWindow └── QGraphicsView└── QGraphicsScene└── QGra…...

【图片识别改名】如何批量将图片按图片上文字重命名?自动批量识别图片文字并命名,基于图片文字内容改名,WPF和京东ocr识别的解决方案
应用场景 在日常工作和生活中,我们经常会遇到需要对大量图片进行重命名的情况。例如,设计师可能需要根据图片内容为设计素材命名,文档管理人员可能需要根据扫描文档中的文字对图片进行分类命名。传统的手动重命名方式效率低下且容易出错&…...

RabbitMQ 的高可用性
RabbitMQ 是比较有代表性的,因为是基于主从(非分布式)做高可用的RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式。 单机模式 单机模式,生产几乎不用。 普通集群模式(无高可用性) 普通集群模…...
DAY 48 随机函数与广播机制
知识点回顾: 随机张量的生成:torch.randn函数卷积和池化的计算公式(可以不掌握,会自动计算的)pytorch的广播机制:加法和乘法的广播机制 ps:numpy运算也有类似的广播机制,基本一致 作…...