• 【redis】redis 锁


    前言

    本文围绕 redis 的 SETNX 命令展开对“锁”的研究与实现。多个进程同时对 redis 执行 SETNX string_key timestamp_expired 命令,只有一个进程会成功,其余都会失败。上述命令中的 string_key 代表被当作锁的 redis 键名,其类型为 String,timestamp_expired 代表该键的过期时间戳,下同。


    软件版本

    • windows 10
    • php 7.4.14 nts
    • thinkphp 6.1.0
    • redis 6.2.7
    • predis/predis 2.0.3(php第三方扩展包)

    锁算法

    算法中使用 redis 的 EVAL 命令保证执行语句的原子性

    申请加锁前需约定锁的有效期、加锁失败后的重试次数、休眠时间(申请加锁时,其他线程加的锁还未过期,休眠一段时间后再重试加锁)。

    申请加锁步骤:

    1. 申请加锁( SETNX string_key timestamp_expired ),如果加锁成功,设置锁的过期时间并返回成功。否则进入步骤 2;
    2. 如果加锁失败原因为 string_key 刚刚被其他进程删除(释放锁),返回步骤 1 重新申请加锁,否则进入步骤 3;
    3. 如果加锁失败原因为 string_key 还未过期(此时也会得到旧的过期时间戳),休眠一段时间后返回步骤 1 重新申请加锁,否则进入步骤 4;
    4. 执行 GETSET string_key timestamp_expired_new 命令,如果命令返回时间戳与旧的过期时间戳相等,加锁成功,设置锁的过期时间并返回成功。否则进入步骤 5;
    5. 锁被其他进程删除了或者被其他进程抢先执行了 GETSET string_key timestamp_expired_new 命令,返回步骤 1 重新申请加锁。

    释放锁:

    如果 string_key 键未被删除且还未过期,执行删除键操作( DEL string_key )。


    实现

    主要类文件有 2 个,为文件 Redis.php(获取 redis 操作客户端) 和 Lock.php(加、释放锁),内容分别如下:

    
    
    namespace app\service;
    
    use Predis\Client;
    use think\facade\Env;
    
    class Redis
    {
       
        /**
         * @var Client $client
         */
        protected $client;
    
        public function __construct()
        {
       
            $this->client = new Client([
                'host' => Env::get('redis.host
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    oracle的序列和触发器
    【PingPong_注册安全分析报告】
    LeetCode:200.岛屿数量
    springboot社区人员管理系统的设计与实现毕业设计源码260839
    C++ Reference: Standard C++ Library reference: C Library: cctype: isblank
    CentOS7图文详细安装教程
    1.4 TCP/IP网络协议
    [山东科技大学OJ]2297 Problem F: 编写函数:字符串的小写转大写(Append Code)
    Git使用经验总结3-删除远端提交记录
    大语言模型(LLM)快速理解
  • 原文地址:https://blog.csdn.net/ZopaulCode/article/details/128152349