Redis实现分布式锁有哪些方案?

在这里分享六种Redis分布式锁的正确使用方式,由易到难。

本文已收录到Java面试网站

方案一:SETNX+EXPIRE

方案二:SETNX+value值(系统时间+过期时间)

方案三:使用Lua脚本(包含SETNX+EXPIRE两条指令)

方案四::ET的扩展命令(SETEXPXNX)

方案五:开源框架~Redisson

方案六:多机实现的分布式锁Redlock

首先什么是分布式锁?

分布式锁是一种机制,用于确保在分布式系统中,多个节点在同一时刻只能有一个节点对共享资源进行操作。它是解决分布式环境下并发控制和数据一致性问题的关键技术之一。

分布式锁的特征:

1、「互斥性」:任意时刻,只有一个客户端能持有锁。

2、「锁超时释放」:持有锁超时,可以释放,防止不必要的资源浪费,也可以防止死锁。

3、「可重入性」“一个线程如果获取了锁之后,可以再次对其请求加锁。

4、「安全性」:锁只能被持有的客户端删除,不能被其他客户端删除

5、「高性能和高可用」:加锁和解锁需要开销尽可能低,同时也要保证高可用,避免分布式锁失效。

Redis分布式锁方案一:SETNX+EXPIRE

提到Redis的分布式锁,很多朋友可能就会想到setnx+expire命令。即先用setnx来抢锁,如果抢到之后,再用expire给锁设置一个过期时间,防止锁忘记了释放。SETNX是SETIF NOT EXISTS的简写。日常命令格式是SETNXkey value,如果 key不存在,则SETNX成功返回1,如果这个key已经存在了,则返回0。假设某电商网站的某商品做秒杀活动,key可以设置为key_resource_id,value设置任意值,伪代码如下:

img

缺陷:加锁与设置过期时间是非原子操作,如果加锁后未来得及设置过期时间系统异常等,会导致其他线程永远获取不到锁。

Redis分布式锁方案二:SETNX+value值(系统时间+过期时间)

为了解决方案一,「发生异常锁得不到释放的场景」,有小伙伴认为,可以把过期时间放到setnx的value值里面。如果加锁失败,再拿出value值校验一下即可。

这个方案的优点是,避免了expire 单独设置过期时间的操作,把「过期时间放到setnx的value值」里面来。解决了方案一发生异常,锁得不到释放的问题。

但是这个方案有别的缺点:过期时间是客户端自己生成的(System.currentTimeMillis()是当前系统的时间),必须要求分布式环境下,每个客户端的时间必须同步。如果锁过期的时候,并发多个客户端同时请求过来,都执行jedis.get()和set(),最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。该锁没有保存持有者的唯一标识,可能坡别的客户端释放/解锁

分布式锁方案三:使用Lua脚本(包含SETNX+EXPIRE两条指令)

实际上,我们还可以使用Lua脚本来保证原子性(包含setnx和expire两条指令),lua脚本如下:

img

加锁代码如下:

img

Redis分布式锁方案四:SET的扩展命令(SET EX PX NX)

除了使用,使用Lua脚本,保证SETNX+EXPIRE两条指令的原子性,我们还可以巧用Redis的SET指令扩展参数。(SET key value[EX seconds]PX milliseconds][NX|XX]`),它也是原子性的

SET key value[EX seconds][PX milliseconds][NX|XX]

  1. NX:表示key不存在的时候,才能set成功,也即保证只有第一个客户端请求才能获得锁,而其他客户端请求只能等其释放锁, 才能获取。
  2. EXseconds:设定key的过期时间,时间单位是秒。
  3. PX milliseconds:设定key的过期时间,单位为毫秒。
  4. XX:仅当key存在时设置值。

伪代码如下:

img

Redis分布式锁方案五:Redisson框架

方案四还是可能存在「锁过期释放,业务没执行完」的问题。设想一下,是否可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。当前开源框架Redisson解决了这个问题。一起来看下Redisson底层原理图:

img

只要线程一加锁成功,就会启动一个watchdog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了「锁过期释放,业务没执行完」问题。

分布式锁方案六:多机实现的分布式锁Redlock+Redisson

前面五种方案都是基于单机版的讨论,那么集群部署该怎么处理?

答案是多机实现的分布式锁Redlock+Redisson

最后分享一份我精心整理的大厂面试手册,包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等高频面试题,非常实用,有小伙伴靠着这份手册拿过字节offer~

需要的小伙伴可以自行下载

链接:http://mp.weixin.qq.com/s?__biz=Mzg2OTY1NzY0MQ==&mid=2247485445&idx=1&sn=1c6e224b9bb3da457f5ee03894493dbc&chksm=ce98f543f9ef7c55325e3bf336607a370935a6c78dbb68cf86e59f5d68f4c51d175365a189f8#rd

posted on 2024-06-11 17:27  程序员大彬  阅读(65)  评论(0编辑  收藏  举报