使用 Redisson 实现分布式锁—解决方案详解

news2025/6/9 9:05:02

在这里插入图片描述

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();  // 计数+1
    try {
        // 内层业务逻辑
    } 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. 客户端宕机处理
客户端 Redis 看门狗线程 获取锁成功(lease=30s) 返回成功 每10秒启动续期检查 续期请求 续期成功 客户端宕机 30秒后自动过期释放锁 客户端 Redis 看门狗线程
2. 网络分区处理
// 使用红锁提高可用性
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.lock(10, TimeUnit.SECONDS); // 设置较短租期

// 添加监听器处理连接丢失
lock.addListener(new LockListener() {
    @Override
    public 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);
    }
    
    @Bean
    public DistributedLockFactory lockFactory(RedissonClient redisson) {
        return new RedissonLockFactory(redisson);
    }
}

@Service
public class OrderService {
    
    @Autowired
    private 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: true
      provider: redisson
      redisson:
        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 分布式锁最佳实践

  1. 锁选择策略

    • 普通场景:RLock 基础锁
    • 读多写少:RReadWriteLock 读写锁
    • 高可用要求:RedissonRedLock 红锁
    • 顺序执行:RedissonFairLock 公平锁
  2. 关键配置参数

    # 看门狗续期时间(默认30秒)
    lockWatchdogTimeout=30000 
    # 锁等待时间(根据业务设置)
    waitTime=5000
    # 锁租期时间(大于业务执行时间)
    leaseTime=30000
    
  3. 性能优化建议

    • 锁粒度最小化
    • 读写锁分离
    • 避免长时间持有锁
    • 热点数据分片
  4. 容灾方案

    • 多数据中心部署
    • 降级策略(本地锁/熔断)
    • 事务补偿机制

最终建议

  • 生产环境使用 Redisson 3.24+ 版本
  • 集群环境使用红锁(至少3个独立主节点)
  • 结合 Prometheus + Grafana 监控锁指标
  • 定期进行混沌工程测试

通过合理使用 Redisson 分布式锁,可以构建出高并发、高可靠的分布式系统。但需谨记:分布式锁是最后的选择而非首选方案,优先考虑无锁设计(如CAS)、事务隔离级别优化等方案能获得更好的系统性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2405166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

结合三维基因建模与智能体技术打造工业软件无码平台

通过深度整合 Protocol Buffers (Protobuf)、gRPC 及 Microsoft AI 技术&#xff0c;构建面向智能制造的高性能、智能化 PLM 平台。 一、Protocol Buffers 深度集成 1. 基因模型标准化定义 三维基因容器 Protobuf 规范&#xff1a; protobuf syntax "proto3"; pa…

Python Day46

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

基于PostGIS的各地级市路网长度统计及Echarts图表可视化实践-以湖南省为例

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

mac版excel如何制作时长版环形图

设置辅助列 创建簇状柱形图 将辅助列绘制在次坐标轴 工作时长在主坐标轴&#xff0c;右键分别更改图表类型为圆环。 辅助列圆环全部为灰色&#xff0c;边框为白色 辅助列设置透明度100% 设置辅助列和工作时长列同样的圆环大小 可得 核心&#xff1a;只要辅助列边框不透明…

【MySQL系列】MySQL 执行 SQL 文件

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

论文MR-SVD

每个像素 7 个 FLOPs意思&#xff1a; FLOPs&#xff08;浮点运算次数&#xff09;&#xff1a;衡量算法计算复杂度的指标&#xff0c;数值越小表示运算越高效。含义&#xff1a;对图像中每个像素进行处理时&#xff0c;仅需执行7 次浮点运算&#xff08;如加减乘除等&#xf…

Java 日期时间类全面解析

Java 日期时间类全面解析&#xff1a;从传统到现代的演进 一、发展历程概览 二、传统日期类&#xff08;Java 8前&#xff09; 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&#xff1a;WireShark 下载、安装、使用 Wireshark下载 阿里云镜像 ■ 通过IP指定查看 ■ ■

设备驱动与文件系统:06 目录与文件

磁盘使用的最后一层抽象&#xff1a;文件系统 今天我们讲第31讲&#xff0c;这一讲将完成磁盘对磁盘使用的最后一层抽象。对此板使用最后一层抽象&#xff0c;抽象出来的是什么呢&#xff1f; 实际上我们使用过磁盘&#xff0c;大家应该有这样的认识&#xff0c;最后不管这个磁…

Linux 系统中的算法技巧与性能优化

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

【C++系列】模板类型特例化

1. C模板类型特例化介绍 ​​定义​​&#xff1a;模板类型特例化&#xff08;Template Specialization&#xff09;是C中为模板的特定类型提供定制实现的机制&#xff0c;允许开发者对通用模板无法处理的特殊类型进行优化或特殊处理。 ​​产生标准​​&#xff1a; C98/03…

K8S认证|CKS题库+答案| 7. Dockerfile 检测

目录 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、修改 Dockerfile 3&#xff09;、 修改 deployment.yaml 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 您必须在以…

基于Scala实现Flink的三种基本时间窗口操作

目录 代码结构 代码解析 (1) 主程序入口 (2) 窗口联结&#xff08;Window Join&#xff09; (3) 间隔联结&#xff08;Interval Join&#xff09; (4) 窗口同组联结&#xff08;CoGroup&#xff09; (5) 执行任务 代码优化 (1) 时间戳分配 (2) 窗口大小 (3) 输出格式…

c++对halcon的动态链接库dll封装及调用(细细讲)

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

【优选算法】分治

一&#xff1a;颜色分类 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…

【图片识别改名】如何批量将图片按图片上文字重命名?自动批量识别图片文字并命名,基于图片文字内容改名,WPF和京东ocr识别的解决方案

应用场景 在日常工作和生活中&#xff0c;我们经常会遇到需要对大量图片进行重命名的情况。例如&#xff0c;设计师可能需要根据图片内容为设计素材命名&#xff0c;文档管理人员可能需要根据扫描文档中的文字对图片进行分类命名。传统的手动重命名方式效率低下且容易出错&…

RabbitMQ 的高可用性

RabbitMQ 是比较有代表性的&#xff0c;因为是基于主从&#xff08;非分布式&#xff09;做高可用的RabbitMQ 有三种模式&#xff1a;单机模式、普通集群模式、镜像集群模式。 单机模式 单机模式,生产几乎不用。 普通集群模式&#xff08;无高可用性&#xff09; 普通集群模…

AI架构师修炼之道

1 AI时代的架构革命 与传统软件开发和软件架构师相比&#xff0c;AI架构师面临着三重范式转换&#xff1a; 1.1 技术维度&#xff0c;需处理异构算力调度与模型生命周期管理的复杂性&#xff1b; 1.2 系统维度&#xff0c;需平衡实时性与资源约束的矛盾&#xff1b; 1.3 价…

iview组件库:当后台返回到的数据与使用官网组件指定的字段不匹配时,进行修改某个属性名再将response数据渲染到页面上的处理

1、需求导入 当存在前端需要的数据的字段渲染到表格或者是一些公共的表格组件展示数据时的某个字段名与后台返回的字段不一致时&#xff0c;那么需要前端进行稍加处理&#xff0c;而不能直接this.list res.data;这样数据是渲染不出来的。 2、后台返回的数据类型 Datalist(pn) …

服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?

系列文章目录 虚拟机 | Ubuntu 安装流程以及界面太小问题解决 虚拟机 | Ubuntu图形化系统&#xff1a; open-vm-tools安装失败以及实现文件拖放 虚拟机 | Ubuntu操作系统&#xff1a;su和sudo理解及如何处理忘记root密码 文章目录 系列文章目录前言一、环境介绍二、 使用syst…