如何用Redis实现分布式锁?RedLock算法的核心思想?Redisson的看门狗机制原理?

一、Redis分布式锁基础实现

public class RedisDistributedLock {private JedisPool jedisPool;private String lockKey;private String clientId;private int expireTime = 30; // 默认30秒public boolean tryLock() {try (Jedis jedis = jedisPool.getResource()) {// NX表示不存在时设置,PX设置过期时间(毫秒)String result = jedis.set(lockKey, clientId, SetParams.setParams().nx().px(expireTime * 1000));return "OK".equals(result);}}public void unlock() {try (Jedis jedis = jedisPool.getResource()) {// 使用Lua脚本保证原子性String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +"   return redis.call('del', KEYS[1]) " +"else " +"   return 0 " +"end";jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(clientId));}}
}

关键点:

  1. 使用SET NX PX命令保证原子性
  • 单命令原子性:Redis服务器单线程顺序执行命令
  • 仅包含SET操作:仅完成键值设置和过期时间配置
  • 无逻辑判断:仅判断键是否存在(NX特性)
  1. 客户端唯一标识(clientId)防止误删
  2. Lua脚本保证解锁操作的原子性
  • 多命令原子性:组合GET、DEL等命令的复合操作
  • 包含业务逻辑:实现"比较后删除"的CAS(Compare And Set)操作
  • 支持复杂流程:可包含条件判断、循环等逻辑

缺陷:
如果锁存在A redis节点,然后B是A的从库,服务先获取A节点的redis key锁,如果A网络波动的时候的时候,主从切换,B节点升级为主节点,这个时候另一个服务获取B节点的相同的redis key,这种情况就发生脑裂了。

二、RedLock算法核心思想

RedLock算法由Redis作者提出,主要解决单点故障问题:

  1. 多节点部署:使用5个(奇数)独立的Redis节点
  2. 顺序获取:客户端依次向所有节点申请锁
  3. 成功条件:获得超过半数的锁(3个)
  4. 耗时计算:总耗时应小于锁的TTL时间
  5. 失败释放:失败时需要释放所有已获得的锁

三、Redisson看门狗机制原理

public class RedissonWatchdogExample {public static void main(String[] args) {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");RedissonClient redisson = Redisson.create(config);RLock lock = redisson.getLock("myLock");try {// 默认30秒过期,看门狗自动续期lock.lock();// 业务逻辑执行时间可能超过30秒Thread.sleep(40000); } finally {lock.unlock();}}
}

集群防止脑裂

Redisson 实现分布式锁的核心机制和集群脑裂防护原理如下:

1. 基础锁实现原理
-- Redis 原子操作脚本
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
2. 集群模式防护机制
// RedissonMultiLock 集群锁实现
List<RLock> locks = new ArrayList<>();
locks.add(redissonClient1.getLock("lock1"));
locks.add(redissonClient2.getLock("lock2"));
RLock multiLock = new RedissonMultiLock(locks.toArray(new RLock[0]));

关键实现要点:

1. 多节点提交机制
  • 需要 N/2+1 个节点成功获取锁才算有效
  • 使用异步线程维持锁心跳(Watchdog 机制)
// Watchdog 线程实现(伪代码)
private void scheduleExpirationRenewal() {if (expirationRenewalMap.putIfAbsent(lockName, newTimeout) == null) {// 每 10 秒续期一次internalLockLeaseTime / 3 周期执行}
}
2. 脑裂防护策略
  • 同步延迟控制:主从同步超时时间 > 锁过期时间
  • 多数派原则:成功获取锁的节点数 > 集群半数节点
  • 故障转移阻断:当节点失联时自动启动锁失效倒计时
3. 异常处理机制
// 锁释放时的集群同步
public void unlock() {for (RLock lock : locks) {if (lock.isHeldByCurrentThread()) {lock.unlockAsync();}}
}

集群模式下重要参数配置建议:

# redisson.yaml
clusterServersConfig:nodeAddresses:- "redis://127.0.0.1:7000"- "redis://127.0.0.1:7001"scanInterval: 1000retryAttempts: 3retryInterval: 500slaveConnectionMinimumIdleSize: 8failedSlaveReconnectionInterval: 30000

该实现通过以下方式保证脑裂场景下的数据一致性:

  1. 使用 Raft 式多数派提交协议
  2. 网络分区时自动降级为只读模式
  3. 主节点切换后新主节点会等待旧主节点锁超时
  4. 客户端自动检测集群拓扑变化并重建连接
    看门狗机制关键点:
  5. 后台线程:每10秒检查锁状态
  6. 自动续期:当业务未完成时,将过期时间重置为30秒
  7. 客户端存活判断:只有客户端保持活跃才会续期
  8. 默认配置:lockWatchdogTimeout=30秒

四、完整方案对比

方案优点缺点
基础Redis锁实现简单单点故障风险
RedLock算法高可用性实现复杂、性能损耗
Redisson实现自动续期、可重入锁、多种锁类型需要维护客户端连接

实际建议:

  1. 单节点场景使用Redisson基础锁
  2. 高可用场景使用Redisson+Redis Cluster
  3. 极端可靠性需求使用RedLock算法

生产环境注意事项:

  1. 合理设置超时时间(业务平均耗时 * 2)
  2. 监控锁等待时间和获取次数
  3. 为不同业务使用不同的锁前缀
  4. 做好锁等待超时的异常处理

竞品分析

分布式锁实现方案对比及优劣势分析

一、ZooKeeper 实现方案
// 使用Curator框架示例
public class ZkDistributedLock {private CuratorFramework client;private InterProcessMutex lock;public boolean tryLock(String lockPath) throws Exception {lock = new InterProcessMutex(client, lockPath);return lock.acquire(3, TimeUnit.SECONDS); // 3秒获取超时}public void unlock() throws Exception {if (lock != null) {lock.release();}}
}

核心原理
通过创建临时顺序节点实现,获取锁的客户端会生成有序节点,只有序号最小的节点持有锁

优势

  1. 自动释放(会话失效时自动删除节点)
  2. 公平锁机制(顺序节点)
  3. 强一致性保证

劣势

  1. 写操作性能低于Redis
  2. 需要维护ZooKeeper集群
  3. 客户端实现相对复杂

二、Etcd 实现方案
// 使用jetcd客户端示例
public class EtcdDistributedLock {private Client client;private Lease lease;public boolean tryLock(String lockKey) throws Exception {lease = client.getLeaseClient().grant(30).get(); // 30秒租约Txn txn = client.getKVClient().txn();txn.If(new Cmp(lockKey, Cmp.Op.EQUAL, CmpTarget.version(0))).Then(Op.put(lockKey, "locked", PutOption.newBuilder().withLeaseId(lease.getID()).build())).Else(Op.get(lockKey));return txn.commit().get().isSucceeded();}
}

核心原理
基于租约(Lease)机制,利用事务操作实现原子性锁获取

优势

  1. 强一致性(Raft协议)
  2. 自动续期机制
  3. 支持公平锁/非公平锁

劣势

  1. 运维复杂度较高
  2. 客户端生态不如Redis完善
  3. 性能低于Redis

三、数据库实现方案
// 基于MySQL的乐观锁实现
public class DbDistributedLock {@Transactionalpublic boolean tryLock(String lockName) {// 使用唯一索引约束int result = jdbcTemplate.update("INSERT INTO distributed_lock(lock_name,owner) VALUES (?,?) ON DUPLICATE KEY UPDATE owner=IF(expire_time < NOW(), VALUES(owner), owner)",lockName, UUID.randomUUID().toString());return result > 0;}
}

核心原理
基于数据库唯一约束或排他锁(SELECT FOR UPDATE)

优势

  1. 无需额外中间件
  2. 实现简单快速

劣势

  1. 性能差(高并发场景容易成为瓶颈)
  2. 无自动释放机制
  3. 死锁风险较高

方案对比总结表

方案一致性性能自动释放实现复杂度适用场景
Redis最终一致支持简单高并发、允许短暂不一致
ZooKeeper强一致支持复杂强一致性要求、公平锁场景
Etcd强一致支持较复杂强一致性且需要自动续期
数据库强一致不支持简单低频访问、无中间件环境的应急方案

选型建议

  1. 追求性能 ➜ Redis(Redisson实现)
  2. 强一致性要求 ➜ ZooKeeper/Etcd
  3. 无中间件环境 ➜ 数据库方案(需谨慎处理超时)
  4. 混合使用场景 ➜ 可组合使用(如Redis做主锁,数据库做备用锁)

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

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

相关文章

前端面试宝典---js垃圾回收机制

什么是垃圾回收 垃圾回收是指一种自动内存管理机制&#xff0c;当声明一个变量时&#xff0c;会在内存中开辟一块内存空间用于存放这个变量。当这个变量被使用过后&#xff0c;可能再也不需要它了&#xff0c;此时垃圾回收器会自动检测并回收这些不再使用的内存空间。垃圾回收…

阿里妈妈LMA2新进展:集成大语言模型与电商知识的通用召回大模型URM

近日&#xff0c;阿里妈妈在国际顶级学术会议 —— 国际万维网大会&#xff08;International World Wide Web Conference, 简称WWW&#xff09;上共同主持了计算广告算法技术相关的Tutorial&#xff08;讲座&#xff09;&#xff0c;介绍了计算广告领域的技术发展脉络&#xf…

数字孪生实时监控汽车零部件工厂智能化巡检新范式

在汽车制造业面临数字化转型时&#xff0c;汽车零部件工厂也面临着提升生产效率、降低运营成本和增强市场竞争力的多重挑战。传统的巡检方式已经难以满足现代工厂对高效、精准管理和实时决策的需求。数字孪生系统的出现&#xff0c;为汽车零部件工厂提供了一种创新的智能化巡检…

【计算机网络】3数据链路层②

1. 数据链路层所处的地位 数据链路层使用的信道主要有两种: ①点对点信道:PPP协议 ②广播信道:有线局域网,CSMA/CD协议;无线局域网,CSMA/CA协议 对比项点对点信道 vs 单播广播信道 vs 广播核心是否一致✅ 一致(一对一传输)✅ 一致(一对所有传输)差异点前者是物理层…

c++中的函数(默认参数,占位参数,重载)

1&#xff0c;函数默认参数 在c中&#xff0c;函数的形参列表中的形参是可以有默认值得 语法&#xff1a;返回值类型 函数名 &#xff08;参数 默认值&#xff09;{} 示例&#xff1a; #include<iostream> using namespace std;//函数默认参数 // 就是如果传了就…

【原创】使用阿里云存放一个临时共享的文件

在某些场合&#xff0c;需要临时将一个文件存储到一个可被公网访问的地方&#xff0c;某个服务需要访问一下这个文件。这个文件基本上就是一次寿命&#xff0c;也就是你上传一下&#xff0c;然后被访问一下&#xff0c;这个文件的寿命就结束了。 对于这种需求&#xff0c;自建…

Python中列表(list)知识详解(2)和注意事项以及应用示例

在 Python 中列表&#xff08;list&#xff09; 的包括其结构、常见操作&#xff08;更新、添加、删除、查找、队列栈行为等&#xff09;&#xff0c;下面将逐一的进行讲解并附相关的示例。 一、列表的基础知识 1. 定义与特点 定义方式&#xff1a;用 [] 包裹的有序可变集合 …

vscode extention踩坑记

# npx vsce package --allow-missing-repository --no-dependencies #耗时且不稳定 npx vsce package --allow-missing-repository #用这行 code --install-extension $vsixFileName --force我问ai&#xff1a;为什么我的.vsix文件大了那么多 ai答&#xff1a;因为你没有用 --n…

移动端巡检点检,让设备管理更便捷高效

在企业设备管理的日常工作中&#xff0c;巡检点检是保障设备正常运行的重要环节。传统的巡检方式依赖纸质记录、人工操作&#xff0c;效率低、易出错&#xff0c;已难以满足现代企业的管理需求。随着技术发展&#xff0c;越来越多设备管理系统引入移动端功能&#xff0c;为设备…

laravel 中使用的pdf 扩展包 laravel-snappy(已解决中文乱码)

Centos7 安装 wkhtmltopdf 1、先查看系统是 32 位的还是 64 位的 uname -a2、通过 composer 安装 wkhtmltopdf 32位: $ composer require h4cc / wkhtmltopdf-i386 0.12.x $ composer require h4cc / wkhtmltoimage-i386 0.12.x 64位: $ composer require h4cc/wkhtmltopdf-…

Rust:重新定义系统编程的安全与效率边界

在软件工程领域&#xff0c;内存安全漏洞每年造成数千亿美元损失&#xff0c;而C/C生态中60%的漏洞源于指针误用。正是在这样的背景下&#xff0c;Rust凭借其革命性的内存安全机制异军突起。作为一门现代系统级编程语言&#xff0c;Rust不仅解决了困扰开发者数十年的内存管理难…

C++学习细节回顾(汇总二)

一.初始化列表相关 1.初始化顺序受申明顺序影响 2.在必要时可以部分不采用初始化列表&#xff0c;避免受特性1影响 二.非类型模板参数 template< class T , size_t N 10 > 三.特化–特殊化处理 template< class T > bool less(T left , T right) { return left&…

勾选某一行的勾选框,更改当前行的颜色,ALV数据发生变化的事件

文章目录 屏幕ALV的创建定义变量注册事件方法定义方法实现frm_data_change 效果 屏幕 ALV的创建 DATA: g_gui_custom_container TYPE REF TO cl_gui_custom_container. DATA: g_gui_alv_grid TYPE REF TO cl_gui_alv_grid.DATA: gt_listheader TYPE slis_t_listheader, &quo…

AI-02a5a6.神经网络-与学习相关的技巧-批量归一化

批量归一化 Batch Normalization 设置合适的权重初始值&#xff0c;则各层的激活值分布会有适当的广度&#xff0c;从而可以顺利的进行学习。那么&#xff0c;更进一步&#xff0c;强制性的调整激活值的分布&#xff0c;是的各层拥有适当的广度呢&#xff1f;批量归一化&#…

解决SQL Server SQL语句性能问题(9)——合理使用表分区

9.2. 合理使用表分区 本专栏4.1.4节中,我们对表分区相关的概念和机制等基础理论进行了较为详细的介绍和论述,读者可以参考该节中内容,或者,读者也可以参考官方或其他相关资料。与其他关系库类似,SQL Server 2005版本中引进的真正意义上的表分区技术,绝对是解决海量数据环…

C语言学习之文件操作

经过前面的学习&#xff0c;我们已经基本掌握了如何去写一个C语言的代码了。但是在实际的项目中&#xff0c;我们不可能不需要文件去操作。因为如果没有文件&#xff0c;我们写的程序是存储在电脑的内存中的。如果程序推出&#xff0c;内存回收数据就随之丢失了。如果我们要对数…

2025年PMP 学习十三 第9章 项目资源管理(9.1,9.2)

2025年PMP 学习十三 第9章 项目资源管理&#xff08;9.1,9.2&#xff09; 序号过程过程组9.1规划资源管理规划9.2估算活动资源规划9.3获取资源执行9.4建设团队执行9.5管理团队执行9.6控制资源监控 文章目录 2025年PMP 学习十三 第9章 项目资源管理&#xff08;9.1,9.2&#xf…

蓝桥杯13届国B 完全日期

题目描述。 如果一个日期中年月日的各位数字之和是完全平方数&#xff0c;则称为一个完全日期。 例如&#xff1a;2021 年 6 月 5 日的各位数字之和为 20216516&#xff0c;而 16 是一个完全平方数&#xff0c;它是 4 的平方。所以 2021 年 6 月 5 日是一个完全日期。 例如&…

某某霸翻译逆向分析[JS逆向]

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经…

开源Heygem本地跑AI数字人视频教程

图文教程&#xff1a; 点击跳转 视频教程 资料包下载 点击下载&#xff1a;