【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(加、释放锁),内容分别如下:

<?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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值