Redis加锁分类
redis加锁命令:incr、setnx、set
第一种:incr
思路:key不存在,key值初始化为0并执行incr进行加1。其他用户执行incr操作进行加1时,返回数大于1,说明锁使用中。
1.A请求获取key,值为1表示获取锁。
2.B请求获取key,值为2表示获取锁失败。
3.A执行完代码,删除锁。
4.B等待一段时间再去请求获取key,值为1获取成功。
5.B执行完代码,删除锁。
$redis -> incr($key);
$redis -> exprie($key,$tt1); //设置生成时间为1秒。
第二种: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,$tt1);
第三种:set
incr和setnx的问题:都需要设置key过期,防止请求执行意外退出了,锁没有删除。但是exprie来设置,就不是原子性操作,还需要事务来确保原子性,但是还是有些问题。
思路:set命令,本身就包含了设置过期时间的功能。
1.A请求设置key的值,设置成功就表示加锁成功。
2.B请求设置key的值,设置失败,表示加锁失败。
3.A执行完代码,删除锁。
4.B等待一段时间再去请求设置key的值,设置成功。
5.B执行代码完成,删除锁。
$redis -> set($key,$value,array('nx','ex' => $tt1)); //ex表示秒
其他问题
1.redis加锁失败怎么办?中断请求还是循环请求?
使用循环请求,循环请求获取锁。
2.循环请求的话,如果有一个获取了锁,其他的再去获取锁的时候,是不是容易发生抢锁的可能?
循环请求获取锁的时候,加入睡眠功能,等待几毫秒再执行循环。
3.锁提前过期,A请求没执行完,B请求获取到了锁,A执行完了,会不会上锁的时候把B的锁给删掉?
在加锁的时候存入的key是随机的,这样的话,每次删除key的时候判断下存入的key里的value和自己存的是否一样。
另外一个锁
官方另外一套加锁的算法。
$servers = [
['127.0.0.1', 6379, 0.01],
['127.0.0.1', 6389, 0.01],
['127.0.0.1', 6399, 0.01],
];
$redLock = new RedLock($servers);
//加锁
$lock = $redLock->lock('my_resource_name', 1000);
//删除锁
$redLock->unlock($lock);