• 【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
  • 相关阅读:
    Chinese ​(Simplified)​ Language Pack / 中文语言包插件
    Seata 与三大平台携手编程之夏,百万奖金等你来拿
    微信加解密流程,证书作用讲解,官方SDK使用教程
    LVGL_文件系统FS
    Python3接口自动化测试项目实战(WEB项目)
    python爬虫之协程
    确诊了!是Druid1.1.20的锅,查询无法映射LocalDateTime类型(带源码解析及解决方案)
    WebGIS 信息系统-Element项目实战
    pod原理
    Linux查看CPU和内存使用情况
  • 原文地址:https://blog.csdn.net/ZopaulCode/article/details/128152349