IT科技类资讯

深入了解redis分布式锁

字号+作者:益华科技来源:应用开发2025-11-05 11:22:59我要评论(0)

深入理解redis分布式锁哈喽,大家好,我是指北君。本篇文件我们来介绍如何Redis实现分布式锁的演进过程,以及为什么不能直接用Setnx实现分布式锁。1、分布式锁简介分布式锁是控制分布式系统不同进程

深入理解redis分布式锁

哈喽,深入式锁大家好,分布我是深入式锁指北君。

本篇文件我们来介绍如何Redis实现分布式锁的分布演进过程,以及为什么不能直接用Setnx实现分布式锁。深入式锁

1、分布分布式锁简介

分布式锁是深入式锁控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的分布系统或同一个系统的不同主机之间共享了某个临界资源,往往需要互斥来防止彼此干扰,深入式锁以保证一致性。分布

业界流行的深入式锁分布式锁实现,一般有这3种方式:

基于数据库实现的分布分布式锁基于Redis实现的分布式锁基于Zookeeper实现的分布式锁

这里主要介绍如何通过 Redis 来实现分布式锁。在介绍 Redis 分布式锁之前,深入式锁我们首先介绍一下实现Redis 分布式锁的分布关键命令。

2、深入式锁setnx

setnx key value

Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。

设置成功,返回 1 。免费信息发布网设置失败,返回 0 。

PS:Redis 官方是不推荐基于 setnx 命令来实现分布式锁的,因为会存在很多问题,

①、单点问题。比如:

客户端A 从master拿到锁lock01master正要把lock01同步(Redis的主从同步通常是异步的)给slave时,突然宕机了,导致lock01没同步给slave主从切换,slave节点被晋级为master节点客户端B到master拿lock01照样能拿到。这样必将导致同一把锁被多人使用。

②、锁的高级用法,比如读写锁、可重入锁等等,setnx 都比较难实现。

这里先介绍基于 sentnx 实现的分布式锁,后面会介绍官方推荐的基于 redisson 来实现分布式锁。

3、Redis-分布式锁-阶段1

接到上文,查询三级分类数据,如果我们部署了多个商品服务,然后多个线程同时去获取三级分类数据,如果不加分布式锁,网站模板就会导致,每一个部署的商品服务第一次查询都会走 DB。

复制public Map<String, List<Catelog2Vo>> getCatelogJsonWithRedisLock() throws InterruptedException { //

一、获取分布式锁

Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111"); if(lock){ // true 表示加锁成功,

执行相关业务

Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb(); stringRedisTemplate.delete("lock"); return dataFromDb; }else{ System.out.println("获取分布式锁失败...等待重试..."); //

加锁失败...重试机制

//

休眠一百毫秒

try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //

自旋的方式

return getCatelogJsonWithRedisLock(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.

4、Redis-分布式锁-阶段2

设置锁自动过期

复制public Map<String, List<Catelog2Vo>> getCatelogJsonWithRedisLock() throws InterruptedException { //

一、获取分布式锁

Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111"); if(lock){ // true 表示加锁成功,

执行相关业务

//

设置过期时间

stringRedisTemplate.expire("lock",30,TimeUnit.SECONDS); Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb(); stringRedisTemplate.delete("lock"); return dataFromDb; }else{ System.out.println("获取分布式锁失败...等待重试..."); //

加锁失败...重试机制

//

休眠一百毫秒

try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //

自旋的方式

return getCatelogJsonWithRedisLock(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.

5、Redis-分布式锁-阶段3

setnx 命令和过期时间保证原子性。

复制public Map<String, List<Catelog2Vo>> getCatelogJsonWithRedisLock() throws InterruptedException { //

一、获取分布式锁

Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111",30,TimeUnit.SECONDS); if(lock){ // true 表示加锁成功,

执行相关业务

//

设置过期时间

//stringRedisTemplate.expire("lock",30,TimeUnit.SECONDS); Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb(); stringRedisTemplate.delete("lock"); return dataFromDb; }else{ System.out.println("获取分布式锁失败...等待重试..."); //

加锁失败...重试机制

//

休眠一百毫秒

try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //

自旋的方式

return getCatelogJsonWithRedisLock(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.

6、Redis-分布式锁-阶段4

保证删除的是自己的锁。

复制public Map<String, List<Catelog2Vo>> getCatelogJsonWithRedisLock() throws InterruptedException { //

一、获取分布式锁

String uuid = UUID.randomUUID().toString(); Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid,30,TimeUnit.SECONDS); if(lock){ // true 表示加锁成功,

执行相关业务

//

设置过期时间

//stringRedisTemplate.expire("lock",30,TimeUnit.SECONDS); Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb(); String lockValue = stringRedisTemplate.opsForValue().get("lock"); if(uuid.equals(lockValue)){ stringRedisTemplate.delete("lock"); } return dataFromDb; }else{ System.out.println("获取分布式锁失败...等待重试..."); //

加锁失败...重试机制

//

休眠一百毫秒

try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //

自旋的方式

return getCatelogJsonWithRedisLock(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.

7、Redis-分布式锁-阶段5

通过Lua脚本保证删除锁和判断锁两个操作原子性

复制public Map<String, List<Catelog2Vo>> getCatelogJsonWithRedisLock(){ //

一、获取分布式锁

String uuid = UUID.randomUUID().toString(); Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid,30,TimeUnit.SECONDS); if (lock) { System.out.println("获取分布式锁成功..."); Map<String, List<Catelog2Vo>> dataFromDb = null; try { //

加锁成功...执行业务

dataFromDb = getDataFromDb(); } finally { String script = "if redis.call(get, KEYS[1]) == ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end"; //

删除锁

stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid); } //

先去redis查询下保证当前的锁是自己的

//获取值对比,对比成功删除=

原子性 lua脚本解锁

// String lockValue = stringRedisTemplate.opsForValue().get("lock"); // if (uuid.equals(lockValue)) { // //

删除我自己的锁

// stringRedisTemplate.delete("lock"); // } return dataFromDb; }else{ System.out.println("获取分布式锁失败...等待重试..."); //

加锁失败...重试机制

//

休眠一百毫秒

try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //

自旋的方式

return getCatelogJsonWithRedisLock(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.

这也是分布式锁的最终模式,需要保证两个点:加锁【设置锁+过期时间】和删除锁【判断+删除】原子性。

香港云服务器

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 九州风神X6(驾临九州风神X6,体验豪华与动感的完美结合)

    九州风神X6(驾临九州风神X6,体验豪华与动感的完美结合)

    2025-11-05 10:36

  • 64位windows 7安装kb3038314补丁更新失败临时解决方法

    64位windows 7安装kb3038314补丁更新失败临时解决方法

    2025-11-05 09:42

  • 如何给windows 7声音设置使工作娱乐无打扰

    如何给windows 7声音设置使工作娱乐无打扰

    2025-11-05 09:37

  • 系统选择界面变成英文的图文解决方法

    系统选择界面变成英文的图文解决方法

    2025-11-05 09:19

网友点评
精彩导读
又该升级系统了,然而14.10版ubuntu该如何才能正常的升级到ubuntu15.04呢?下面我将升级我自己的系统。1、点击菜单中的设置。因为桌面软件的改变,所以,现在有设置直接能对我们电脑进行配置调整,我们这里先点击设置图标。2。在设置中。里面有很多项目,其中系统项目里面,我们点击【软件和更新】这个图标,如下图3、软件和更新窗口可以更新系统,也可以更新软件。点击【更新】栏,设置成提示更新的方式为【每天】和有新版本时通知我设置为【适用任何新版本】,然后关掉软件和更新窗口,之后系统假如在联网就会提示你是否更新。4、在更新提示窗口。 我们目的是为了更新,那么就点击【立即安装】5、然后是一个全英文的界面。因为我现在的系统版本是14.10,然后提示有15.04这个新的ubuntu版本,那么我就点击【升级(U)】6、系统根据你的点击升级进入到下一个界面。点击升级按钮后,我的系统便开始下载升级安装包啦。一共有六步,等待前一步完成后才会进入下一步。7、建议不要再升级过程中点击【取消】按钮。但是系统会再一次提示你【您要开始升级么?】。此时,假如你不想升级,那么点击取消按钮还来得及,否则请点击【立即升级】按钮。8、这样系统开始正式升级啦,期间不要断电,或者点击取消,否则会发生意料之外的结果9、最后,系统升级完成,询问你是否清除安装包。建议您点击【删除】,然后点击【现在重启】,系统重启后,则升级完成!

又该升级系统了,然而14.10版ubuntu该如何才能正常的升级到ubuntu15.04呢?下面我将升级我自己的系统。1、点击菜单中的设置。因为桌面软件的改变,所以,现在有设置直接能对我们电脑进行配置调整,我们这里先点击设置图标。2。在设置中。里面有很多项目,其中系统项目里面,我们点击【软件和更新】这个图标,如下图3、软件和更新窗口可以更新系统,也可以更新软件。点击【更新】栏,设置成提示更新的方式为【每天】和有新版本时通知我设置为【适用任何新版本】,然后关掉软件和更新窗口,之后系统假如在联网就会提示你是否更新。4、在更新提示窗口。 我们目的是为了更新,那么就点击【立即安装】5、然后是一个全英文的界面。因为我现在的系统版本是14.10,然后提示有15.04这个新的ubuntu版本,那么我就点击【升级(U)】6、系统根据你的点击升级进入到下一个界面。点击升级按钮后,我的系统便开始下载升级安装包啦。一共有六步,等待前一步完成后才会进入下一步。7、建议不要再升级过程中点击【取消】按钮。但是系统会再一次提示你【您要开始升级么?】。此时,假如你不想升级,那么点击取消按钮还来得及,否则请点击【立即升级】按钮。8、这样系统开始正式升级啦,期间不要断电,或者点击取消,否则会发生意料之外的结果9、最后,系统升级完成,询问你是否清除安装包。建议您点击【删除】,然后点击【现在重启】,系统重启后,则升级完成!