redis,谈谈分布式锁

redis,谈谈分布式锁

分布式锁

锁是什么

锁是解决多线程问题,多线程去处理同一处代码,因为线程是无序的会造成数据错乱,java里处理这种问题有synchronized和ReentrantLock还有threadLocal等等去解决线程安全问题。
但是当项目的用户越来越多,系统架构采用分布式,单单synchronized和RenntrantLock并不能解决分布式中的资源抢夺。所以有了新的解决方案。
基于数据库的分布式锁
redis分布式锁
zookeeper分布式锁

这里先介绍redis分布式锁。

redis分布式锁

redis中的get和set命令并不是原子性的,众所周知锁必须满足原子性(关于原子性是什么可以百度下)。

那么redis怎么去实现原子性操作呢。

执行setnx ->执行业务代码->执行del
在setnx和del命令中执行的你业务代码。

SETNX  key value

返回值:
key不存在 = 1
key存在 = 0

这里存在一个问题啊。
如果在执行setnx之后断点了。del命令并没有执行,会造成死锁,锁得不到释放,会一直占用资源。
所以在setnx之后设置一个expire存活时间

->setnx key value
ok
->expire key 5
这里写上你的业务代码........
->del key
(integer) 1

但是还有存在一个问题.
如果在setnx和expire之间机器挂掉,还是会造成死锁.因为setnx和expire操作并不是同时执行的,不是原子操作.

所以在redis2.8version中加入了set执行的扩展函数,保证setnx和expire可以同时执行.彻底解决了分布式锁的乱象.

->set key value ex 5 nx
OK
执行你的业务代码
->del key
(integer) 1

综上所述,setnx和expire两个同时执行就是redis分布式锁的奥秘所在

为了保证超时问题,第一个线程持有的锁过期了,导致代码没有执行完,而同时第二个线程提前重新持有了这把锁,在set指令的时候为value设定一个随机值,释放锁的时候匹配随机值,然后在删除key,这是为了确保当前线程占有的锁不会被其他线程释放,除非这个锁是过期释放的。

random.nextint()

但是匹配随机值和删除key并不是一个原子操作,redis提供了lua脚本来实现原子操作

if redis.call("get",KEYS[1]) == ARGV[1] then
 	return redis.call("del",KEYS[1])
else
	return 0
end

以上。

这里有个tip,经验所得,如果不知道过期时间等于多少的话,
可以这样设置
过期时间=业务处理时间*2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值