redis实现加锁的几种方法示例详解
前言
本文主要给大家介绍了关于redis实现加锁的几种方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
1.redis加锁分类
redis能用的的加锁命令分表是INCR、SETNX、SET
2.第一种锁命令INCR
这种加锁的思路是,key不存在,那么key的值会先被初始化为0,然后再执行INCR操作进行加一。
然后其它用户在执行INCR操作进行加一时,如果返回的数大于1,说明这个锁正在被使用当中。
1、客户端A请求服务器获取key的值为1表示获取了锁
2、客户端B也去请求服务器获取key的值为2表示获取锁失败
3、客户端A执行代码完成,删除锁
4、客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功
5、客户端B执行代码完成,删除锁
$redis->incr($key); $redis->expire($key,$ttl);//设置生成时间为1秒
3.第二种锁SETNX
这种加锁的思路是,如果key不存在,将key设置为value
如果key已存在,则SETNX不做任何动作
1、客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
2、客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
3、客户端A执行代码完成,删除锁
4、客户端B在等待一段时间后在去请求设置key的值,设置成功
5、客户端B执行代码完成,删除锁
$redis->setNX($key,$value); $redis->expire($key,$ttl);
4.第三种锁SET
上面两种方法都有一个问题,会发现,都需要设置key过期。那么为什么要设置key过期呢?如果请求执行因为某些原因意外退出了,导致创建了锁但是没有删除锁,那么这个锁将一直存在,以至于以后缓存再也得不到更新。于是乎我们需要给锁加一个过期时间以防不测。
但是借助Expire来设置就不是原子性操作了。所以还可以通过事务来确保原子性,但是还是有些问题,所以官方就引用了另外一个,使用SET命令本身已经从版本2.6.12开始包含了设置过期时间的功能。
1、客户端A请求服务器设置key的值,如果设置成功就表示加锁成功
2、客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败
3、客户端A执行代码完成,删除锁
4、客户端B在等待一段时间后在去请求设置key的值,设置成功
5、客户端B执行代码完成,删除锁
$redis->set($key,$value,array('nx','ex'=>$ttl));//ex表示秒
5.其它问题
虽然上面一步已经满足了我们的需求,但是还是要考虑其它问题?
1、redis发现锁失败了要怎么办?中断请求还是循环请求?
2、循环请求的话,如果有一个获取了锁,其它的在去获取锁的时候,是不是容易发生抢锁的可能?
3、锁提前过期后,客户端A还没执行完,然后客户端B获取到了锁,这时候客户端A执行完了,会不会在删锁的时候把B的锁给删掉?
6.解决办法
针对问题1:使用循环请求,循环请求去获取锁
针对问题2:针对第二个问题,在循环请求获取锁的时候,加入睡眠功能,等待几毫秒在执行循环
针对问题3:在加锁的时候存入的key是随机的。这样的话,每次在删除key的时候判断下存入的key里的value和自己存的是否一样
do{//针对问题1,使用循环 $timeout=10; $roomid=10001; $key='room_lock'; $value='room_'.$roomid;//分配一个随机的值针对问题3 $isLock=Redis::set($key,$value,'ex',$timeout,'nx');//ex秒 if($isLock){ if(Redis::get($key)==$value){//防止提前过期,误删其它请求创建的锁 //执行内部代码 Redis::del($key); continue;//执行成功删除key并跳出循环 } }else{ usleep(5000);//睡眠,降低抢锁频率,缓解redis压力,针对问题2 } }while(!$isLock);
7.另外一个锁
以上的锁完全满足了需求,但是官方另外还提供了一套加锁的算法,这里以PHP为例
$servers=[ ['127.0.0.1',6379,0.01], ['127.0.0.1',6389,0.01], ['127.0.0.1',6399,0.01], ]; $redLock=newRedLock($servers); //加锁 $lock=$redLock->lock('my_resource_name',1000); //删除锁 $redLock->unlock($lock)
上面是官方提供的一个加锁方法,就是和第6的大体方法一样,只不过官方写的更健壮。所以可以直接使用官方提供写好的类方法进行调用。官方提供了各种语言如何实现锁。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。