Redis实现分布式锁有哪些方案?
在这里分享六种Redis分布式锁的正确使用方式,由易到难。
方案一: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设置任意值,伪代码如下:
缺陷:加锁与设置过期时间是非原子操作,如果加锁后未来得及设置过期时间系统异常等,会导致其他线程永远获取不到锁。
Redis分布式锁方案二:SETNX+value值(系统时间+过期时间)
为了解决方案一,「发生异常锁得不到释放的场景」,有小伙伴认为,可以把过期时间放到setnx的value值里面。如果加锁失败,再拿出value值校验一下即可。
这个方案的优点是,避免了expire 单独设置过期时间的操作,把「过期时间放到setnx的value值」里面来。解决了方案一发生异常,锁得不到释放的问题。
但是这个方案有别的缺点:过期时间是客户端自己生成的(System.currentTimeMillis()是当前系统的时间),必须要求分布式环境下,每个客户端的时间必须同步。如果锁过期的时候,并发多个客户端同时请求过来,都执行jedis.get()和set(),最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。该锁没有保存持有者的唯一标识,可能坡别的客户端释放/解锁
分布式锁方案三:使用Lua脚本(包含SETNX+EXPIRE两条指令)
实际上,我们还可以使用Lua脚本来保证原子性(包含setnx和expire两条指令),lua脚本如下:
加锁代码如下:
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]
- NX:表示key不存在的时候,才能set成功,也即保证只有第一个客户端请求才能获得锁,而其他客户端请求只能等其释放锁, 才能获取。
- EXseconds:设定key的过期时间,时间单位是秒。
- PX milliseconds:设定key的过期时间,单位为毫秒。
- XX:仅当key存在时设置值。
伪代码如下:
Redis分布式锁方案五:Redisson框架
方案四还是可能存在「锁过期释放,业务没执行完」的问题。设想一下,是否可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。当前开源框架Redisson解决了这个问题。一起来看下Redisson底层原理图:
只要线程一加锁成功,就会启动一个watchdog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了「锁过期释放,业务没执行完」问题。
分布式锁方案六:多机实现的分布式锁Redlock+Redisson
前面五种方案都是基于单机版的讨论,那么集群部署该怎么处理?
答案是多机实现的分布式锁Redlock+Redisson
最后分享一份我精心整理的大厂面试手册,包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等高频面试题,非常实用,有小伙伴靠着这份手册拿过字节offer~
需要的小伙伴可以自行下载: