浅谈分布式锁实现原理

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 浅谈分布式锁实现原理

本篇讲的是基于redis实现的分布式锁

很多程序员都知道redis有个命令叫setnx,它可以给我们的redis加锁

执行这个命令,如果它判断这个锁的名字,也就是key存在的时候,不做操作

假设我这里有段代码,我需要给他加锁以保证线程安全,解决分布式下的资源共享问题

String lockKey = "myLock";
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "achao");  //加锁
if (!result) {
    throw new Exception("error!");
}
//执行业务
System.out.println("执行业务");
stringRedisTemplate.delete(lockKey);  //释放锁

现在有个问题,就是如果我按上面这样写,如果我们中途程序执行的时候抛出了一个异常,那么我们的锁就永远得不到释放,下一个线程过来,发现锁没释放,就导致整个系统卡死

为了解决这个问题,我们加上try/finally语句

String lockKey = "myLock";
Boolean result;
try {
    result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "achao");
    if (!result) {
        throw new Exception("error!");
    }
    //执行业务
    System.out.println("执行业务");
} finally {
    stringRedisTemplate.delete(lockKey);      //释放锁
}

这样之后,程序执行出了异常,咱们的锁也能得到释放了

但是如果执行到一半,程序挂了。。。比如服务器死机,或者重启等等,这样我们的锁还是得不到释放

所以,我们可以给这个锁设置个有效期

String lockKey = "myLock";
Boolean result;
try {
    result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "achao");   //加锁
    stringRedisTemplate.expire(lockKey, 30, TimeUnit.SECONDS);    //设置有效期
    if (!result) {
        throw new Exception("error!");
    }
    //执行业务
    System.out.println("执行业务");
} finally {
    stringRedisTemplate.delete(lockKey);
}

但这样还有个问题。。。

我在执行第一句加锁,刚执行完,我第二句设置有效期还没执行,这。。。就跟上面一样了

所以我们又来,把它俩合成一条代码

result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "achao",10,TimeUnit.SECONDS);

这样,就不会出现那种问题了,但你以为这就结束了???

不!

设想,在高并发下,我们第一个线程进来,他的锁有效期是10秒,但他执行了15秒,在10秒的时候他的锁有效期到了,这时候,他释放了锁。

第二个线程,他的锁有效期也是十秒,他在第一个线程执行到10秒的时候开始执行,它看到前面的锁已经失效,那么他又可以加锁了!

这个时候!

两个线程再执行了5秒,第一个线程执行完业务逻辑,到了finally语句的时候,他执行释放锁的操作,可是这个锁。。。是第二个线程的锁!

然后第三个线程,它发现前面的锁被释放掉了,然后它又可以加锁了。。。

第二个线程执行到finally的时候又释放了第三把锁。。。

这样我们就相当于没有锁了

我们这个时候就需要给requestId一个随机值

String lockKey = "myLock";
Boolean result;
String requestId = UUID.randomUUID().toString();  //生成随机值
try {
    result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS);
    if (!result) {
        throw new Exception("error!");
    }
    //执行业务
    System.out.println("执行业务");
} finally {
    if (requestId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
        stringRedisTemplate.delete(lockKey);
    }
}

这样,就不会删除到别的线程的锁了

然而,这个时间设置很令人头疼,如果锁失效时间设置为5s,可能太少,但如果设置为30s,也可能不够。。。比如mysql执行卡住了,遇到了慢查询之类的

但如果我设置非常久。。。比如设置个30分钟,那如果执行到finally之前服务器死机了,这样就变成30分钟锁释放了才能再执行下一个线程了。。。

所以我们一般采用锁续命的方式:

新建一个分支线程,设置一个定时任务,比如每10s判断一下线程还活着没,如果这个线程存在,就把expire再设置成30s,重置锁的失效时间

这就是分布式锁的底层原理了,具体实现这个锁续命的操作,可以使用redisson

redisson调用LUA脚本(一个小众化脚本语言)实现,用的hash保证原子性,内部机制采用C语言实现

String lockKey = "myLock";
RLock lock = redisson.getLock(lockKey);         //1 获得锁对象
try {
    lock.lock();          //2  加锁(默认设置了有效时间,并开启分支线程定时续命)
    //业务
    System.out.println("业务");
}finally {
    lock.unlock();        //3  解锁
}

就这样,redisson帮我们做了以上所有操作,一个很漂亮的分布式锁,就只需要这三行代码

相关文章
|
存储 分布式计算 Hadoop
Hadoop【基础知识 01】【分布式文件系统HDFS设计原理+特点+存储原理】(部分图片来源于网络)
【4月更文挑战第3天】Hadoop【基础知识 01】【分布式文件系统HDFS设计原理+特点+存储原理】(部分图片来源于网络)
540 3
|
5月前
|
NoSQL 算法 安全
分布式锁—1.原理算法和使用建议
本文主要探讨了Redis分布式锁的八大问题,包括非原子操作、忘记释放锁、释放其他线程的锁、加锁失败处理、锁重入问题、锁竞争问题、锁超时失效及主从复制问题,并提供了相应的优化措施。接着分析了Redis的RedLock算法,讨论其优缺点以及分布式专家Martin对其的质疑。此外,文章对比了基于Redis和Zookeeper(zk)的分布式锁实现原理,包括获取与释放锁的具体流程。最后总结了两种分布式锁的适用场景及使用建议,指出Redis分布式锁虽有性能优势但模型不够健壮,而zk分布式锁更稳定但部署成本较高。实际应用中需根据业务需求权衡选择。
|
8月前
|
运维 NoSQL 算法
【📕分布式锁通关指南 04】redis分布式锁的细节问题以及RedLock算法原理
本文深入探讨了基于Redis实现分布式锁时遇到的细节问题及解决方案。首先,针对锁续期问题,提出了通过独立服务、获取锁进程自己续期和异步线程三种方式,并详细介绍了如何利用Lua脚本和守护线程实现自动续期。接着,解决了锁阻塞问题,引入了带超时时间的`tryLock`机制,确保在高并发场景下不会无限等待锁。最后,作为知识扩展,讲解了RedLock算法原理及其在实际业务中的局限性。文章强调,在并发量不高的场景中手写分布式锁可行,但推荐使用更成熟的Redisson框架来实现分布式锁,以保证系统的稳定性和可靠性。
372 0
【📕分布式锁通关指南 04】redis分布式锁的细节问题以及RedLock算法原理
|
监控 NoSQL Java
分布式锁实现原理问题之ZooKeeper的观察器(Watcher)特点问题如何解决
分布式锁实现原理问题之ZooKeeper的观察器(Watcher)特点问题如何解决
121 0
|
NoSQL Java Redis
分布式锁实现原理问题之使用Redis的setNx命令来实现分布式锁问题如何解决
分布式锁实现原理问题之使用Redis的setNx命令来实现分布式锁问题如何解决
225 0
|
11月前
|
存储 Dubbo Java
分布式 RPC 底层原理详解,看这篇就够了!
本文详解分布式RPC的底层原理与系统设计,大厂面试高频,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式 RPC 底层原理详解,看这篇就够了!
|
存储 分布式计算 监控
Hadoop【基础知识 01+02】【分布式文件系统HDFS设计原理+特点+存储原理】(部分图片来源于网络)【分布式计算框架MapReduce核心概念+编程模型+combiner&partitioner+词频统计案例解析与进阶+作业的生命周期】(图片来源于网络)
【4月更文挑战第3天】【分布式文件系统HDFS设计原理+特点+存储原理】(部分图片来源于网络)【分布式计算框架MapReduce核心概念+编程模型+combiner&partitioner+词频统计案例解析与进阶+作业的生命周期】(图片来源于网络)
569 2
|
10月前
|
机器学习/深度学习 存储 运维
分布式机器学习系统:设计原理、优化策略与实践经验
本文详细探讨了分布式机器学习系统的发展现状与挑战,重点分析了数据并行、模型并行等核心训练范式,以及参数服务器、优化器等关键组件的设计与实现。文章还深入讨论了混合精度训练、梯度累积、ZeRO优化器等高级特性,旨在提供一套全面的技术解决方案,以应对超大规模模型训练中的计算、存储及通信挑战。
545 4
|
11月前
|
NoSQL Java API
分布式锁的实现原理与应用场景,5 分钟彻底搞懂!
本文详细解析了分布式锁的实现原理与应用场景,包括线程锁、进程锁和分布式锁的区别,以及分布式锁的四种要求和三种实现方式(数据库乐观锁、ZooKeeper、Redis)。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式锁的实现原理与应用场景,5 分钟彻底搞懂!
|
12月前
|
分布式计算 Hadoop 网络安全
Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件
Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件
150 1

热门文章

最新文章