解锁redis锁的正确姿势

 更新时间:2017年03月22日 10:59:41   作者:叶剑峰  
这篇文章主要为大家详细介绍了解锁redis锁的正确姿势,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

解锁redis锁的正确姿势

redis是php的好朋友,在php写业务过程中,有时候会使用到锁的概念,同时只能有一个人可以操作某个行为。这个时候我们就要用到锁。锁的方式有好几种,php不能在内存中用锁,不能使用zookeeper加锁,使用数据库做锁又消耗比较大,这个时候我们一般会选用redis做锁机制。

setnx

锁在redis中最简单的数据结构就是string。最早的时候,上锁的操作一般使用setnx,这个命令是当:lock不存在的时候set一个val,或许你还会记得使用expire来增加锁的过期,解锁操作就是使用del命令,伪代码如下:

if (Redis::setnx("my:lock", 1)) {
  Redis::expire("my:lock", 10);
  // ... do something

  Redis::del("my:lock")
}

这里其实是有问题的,问题就在于setnx和expire中间如果遇到crash等行为,可能这个lock就不会被释放了。于是进一步的优化方案可能是在lock中存储timestamp。判断timestamp的长短。

set

现在官方建议直接使用set来实现锁。我们可以使用set命令来替代setnx,就是下面这个样子

if (Redis::set("my:lock", 1, "nx", "ex", 10)) {
  ... do something

  Redis::del("my:lock")
}

上面的代码把my:lock设置为1,当且仅当这个lock不存在的时候,设置完成之后设置过期时间为10。

获取锁的机制是对了,但是删除锁的机制直接使用del是不对的。因为有可能导致误删别人的锁的情况。

比如,这个锁我上了10s,但是我处理的时间比10s更长,到了10s,这个锁自动过期了,被别人取走了,并且对它重新上锁了。那么这个时候,我再调用Redis::del就是删除别人建立的锁了。

官方对解锁的命令也有建议,建议使用lua脚本,先进行get,再进行del

程序变成:

$token = rand(1, 100000);

function lock() {
  return Redis::set("my:lock", $token, "nx", "ex", 10);
}

function unlock() {
  $script = `
if redis.call("get",KEYS[1]) == ARGV[1]
then
  return redis.call("del",KEYS[1])
else
  return 0
end  
  `
  return Redis::eval($script, "my:lock", $token)
}

if (lock()) {
  // do something

  unlock();
}

这里的token是一个随机数,当lock的时候,往redis的my:lock中存的是这个token,unlock的时候,先get一下lock中的token,如果和我要删除的token是一致的,说明这个锁是之前我set的,否则的话,说明这个锁已经过期,是别人set的,我就不应该对它进行任何操作。

所以:不要再使用setnx,直接使用set进行锁实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Redis中一些最常见的面试问题总结

    Redis中一些最常见的面试问题总结

    Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行各种刁难。下面这篇文章主要给大家总结介绍了关于Redis中一些最常见的面试问题,需要的朋友可以参考下
    2018-09-09
  • Redis分布式锁如何设置超时时间

    Redis分布式锁如何设置超时时间

    这篇文章主要介绍了Redis分布式锁如何设置超时时间,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Redisson如何解决Redis分布式锁提前释放问题

    Redisson如何解决Redis分布式锁提前释放问题

    本文主要介绍了Redisson如何解决Redis分布式锁提前释放问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • redis启动和退出命令行简单操作步骤

    redis启动和退出命令行简单操作步骤

    Redis是一种键值存储数据库,用户可以使用它来存储和检索大量的键值数据,下面这篇文章主要给大家介绍了关于redis启动和退出命令行的相关资料,需要的朋友可以参考下
    2024-03-03
  • redis缓存的简单操作(get、put)

    redis缓存的简单操作(get、put)

    这篇文章主要介绍了redis缓存的简单操作,包括引入jedisjar包、配置redis、RedisDao需要的一些工具等,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • 详解Redis主从复制实践

    详解Redis主从复制实践

    本文将演示主从复制如何配置、实现以及实现原理,Redis主从复制三大策略,全量复制、部分复制和立即复制。
    2021-05-05
  • redis yml配置的用法小结

    redis yml配置的用法小结

    RedisYML配置是Redis的一种配置文件格式,,对Redis的配置进行统一管理,本文就来介绍了redis yml配置的用法小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • redis中使用java脚本实现分布式锁

    redis中使用java脚本实现分布式锁

    这篇文章主要介绍了redis中使用java脚本实现分布式锁,本文同时讲解了java脚本和lua脚本实现分布式锁,需要的朋友可以参考下
    2015-01-01
  • 浅谈内存耗尽后Redis会发生什么

    浅谈内存耗尽后Redis会发生什么

    这篇文章主要介绍了浅谈内存耗尽后Redis会发生什么,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • redis数据的两种持久化方式对比

    redis数据的两种持久化方式对比

    Redis是我们开发中常用的数据库,今天和大家分享的就是redis持久化的2种方式:RDB(Redis DataBase)和AOF(Apend Only File),希望对大家学习redis有帮助,一起来看看吧。
    2017-08-08

最新评论