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

Redisson实现Redis分布式锁的原理

Redisson是一个基于Redis的Java驻内存数据网格(In-Memory Data Grid)客户端,它提供了丰富的分布式对象和服务,其中分布式锁是其核心功能之一。

基本原理

Redisson的分布式锁实现主要依赖Redis的以下特性:

  1. 单线程模型:Redis的单线程特性确保命令执行的原子性

  2. 键过期机制:通过EXPIRE命令实现锁的自动释放

  3. Lua脚本:保证复杂操作的原子性执行

核心实现机制

1. 加锁过程

lua

复制

下载

-- Redisson加锁的Lua脚本核心逻辑
if (redis.call('exists', KEYS[1]) == 0) thenredis.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) thenredis.call('hincrby', KEYS[1], ARGV[2], 1)redis.call('pexpire', KEYS[1], ARGV[1])return nil
end
return redis.call('pttl', KEYS[1])

参数说明

  • KEYS[1]:锁的key名

  • ARGV[1]:锁的过期时间(毫秒)

  • ARGV[2]:客户端唯一标识(通常由UUID+线程ID组成)

执行流程

  1. 检查锁key是否存在

  2. 如果不存在,使用hash结构设置锁,并设置过期时间

  3. 如果已存在且是当前客户端持有,则重入计数+1,并刷新过期时间

  4. 如果被其他客户端持有,返回锁的剩余生存时间

2. 可重入实现

Redisson通过Redis的Hash结构实现可重入锁:

  • Hash的field为客户端唯一标识

  • Hash的value为锁的重入次数

3. 锁续期机制(Watchdog)

java

复制

下载

// Redisson的看门狗线程核心逻辑
private void scheduleExpirationRenewal() {// 每隔锁过期时间的1/3时间续期一次Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {@Overridepublic void run(Timeout timeout) {// 通过Lua脚本续期expireAsync(threadId);}}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
}

特性

  • 默认锁超时时间30秒

  • 每10秒(30/3)检查一次,如果锁仍被持有,则延长锁的过期时间

  • 只在未显式指定leaseTime时启用

4. 解锁过程

lua

复制

下载

-- Redisson解锁的Lua脚本核心逻辑
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) thenreturn nil
end
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1)
if (counter > 0) thenredis.call('pexpire', KEYS[1], ARGV[2])return 0
elseredis.call('del', KEYS[1])redis.call('publish', KEYS[2], ARGV[1])return 1
end
return nil

执行流程

  1. 检查锁是否存在且是否由当前客户端持有

  2. 如果是,则重入计数-1

  3. 如果重入计数>0,刷新过期时间

  4. 如果重入计数=0,删除锁key并发布解锁消息

关键特性

  1. 互斥性:同一时刻只有一个客户端能持有锁

  2. 避免死锁:锁自动过期释放 + 看门狗自动续期

  3. 可重入性:同一线程可多次获取同一把锁

  4. 容错性:Redis节点宕机时,锁会自动释放

  5. 公平锁支持:通过Redis的队列实现

锁类型

Redisson提供了多种分布式锁实现:

  1. 普通锁(RLock):最基本的可重入锁

  2. 公平锁(FairLock):按照请求顺序获取锁

  3. 联锁(MultiLock):同时对多个锁加锁

  4. 红锁(RedLock):基于多个独立Redis节点的分布式锁

  5. 读写锁(RReadWriteLock):读-写分离的锁

红锁(RedLock)算法

Redisson实现了Redis官方推荐的RedLock算法,用于提高分布式锁的可靠性:

  1. 获取当前时间(毫秒)

  2. 依次尝试从N个独立的Redis实例获取锁

  3. 计算获取锁花费的总时间(当前时间 - 步骤1时间)

    • 只有当大多数(N/2+1)节点获取成功

    • 且总耗时小于锁有效时间,才认为获取成功

  4. 锁的真正有效时间 = 初始有效时间 - 获取锁花费的时间

  5. 如果获取失败,则向所有节点发起解锁请求

使用示例

java

复制

下载

// 获取锁
RLock lock = redisson.getLock("myLock");
try {// 尝试加锁,最多等待100秒,上锁后30秒自动解锁boolean isLocked = lock.tryLock(100, 30, TimeUnit.SECONDS);if (isLocked) {// 执行业务逻辑}
} catch (InterruptedException e) {Thread.currentThread().interrupt();
} finally {// 释放锁if (lock.isHeldByCurrentThread()) {lock.unlock();}
}

注意事项

  1. 网络分区问题:Redis集群发生网络分区时可能导致锁失效

  2. 性能考量:频繁的锁操作会增加Redis负担

  3. 锁粒度:锁的粒度应尽可能小,避免长时间持有锁

  4. 异常处理:确保锁最终能被释放,防止死锁

  5. 时钟漂移:在Redis集群中,时钟不同步可能影响锁的有效性

http://www.dtcms.com/a/309089.html

相关文章:

  • Windows和Linux的tree工具
  • 【智能协同云图库】第七期:基于AI调用阿里云百炼大模型,实现AI图片编辑功能
  • 渗透测试报告通常包含哪些关键内容?
  • redis快速部署、集成、调优
  • Linux通用SPI作为Master——回环测试
  • Redis学习-----Redis的基本数据类型
  • Dify版本升级实操
  • Edge中如何找到原IE浏览器的Internet选项
  • 基于html,css,jquery,django,lstm,cnn,tensorflow,bert,推荐算法,mysql数据库
  • 8月1日RED指令强制生效,您的设备准备好了吗?
  • uniapp 开发微信小程序,获取经纬度(uni.getLocation)并且转化详细地址(‌高德地图逆地理编码API、‌腾讯地图逆地理编码)
  • 【华为机试】127. 单词接龙
  • Python match-case 模式匹配详解
  • 【Mysql】字段隐式转换对where条件和join关联条件的影响
  • 【Java面试题】缓存穿透
  • 什么是doris
  • 优化网站域名的SEO策略指南
  • Qt开发中的安全技术问题详解
  • MySQL(172)如何进行MySQL的全局变量设置?
  • 深度揭秘端口映射:原理、场景、路由映射故障,与内网IP端口映射外网工具的选择
  • 微服务消息队列之RabbitMQ,深入了解
  • 逻辑斯蒂回归的模型优化
  • IO流-文件实例
  • MySQL--组从复制的详解及功能演练
  • 数据赋能(371)——数据挖掘——概述
  • java的冒泡排序算法
  • 从O(n²)到O(n log n):深度剖析快速排序的内存优化与cache-friendly实现
  • Java Map和Set
  • Vue 3.5 defineModel:让组件开发效率提升 10 倍
  • 自行实现log2对数运算