php redis分布式锁

一,概念

在PHP中实现分布式锁通常可以使用数据库、缓存系统(如Redis)或者其他中央存储系统来保证在分布式系统中的数据一致性与同步。秒杀下单、抢红包等等业务场景,都需要用到分布式锁。

常规方案大概有七中

方案一:SETNX + EXPIRE

方案二:SETNX + value值是(系统时间+过期时间)

方案三:使用Lua脚本(包含SETNX + EXPIRE两条指令)

方案四:SET的扩展命令(SET EX PX NX)

方案五:SET EX PX NX + 校验唯一随机值,再释放锁

方案六: 开源框架~Redisson

方案七:多机实现的分布式锁Redlock

这里我采用方案三,加锁和根据判断解锁都需要保持原子性,所以使用Lua脚本

二、代码

php 复制代码
<?php

class RedisLock
{
    private $redis;
    private $lockKey;

    public function __construct($lockKey)
    {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
        $this->lockKey = $lockKey;
    }

    public function acquireLock()
    {
        // 设置锁的超时时间,防止死锁(在删除锁的时候有可能服务挂了,那这个锁就成了死锁,设置过期时间可以防止死锁)
        $expire = 10;
        // 生成一个唯一的标识符(可能会出现线程A代码未执行完,锁已经过期,这时候另外一个线程B就能拿到了锁,这时线程A执行完毕删除锁,如果没有当前线程唯一标识就会删除掉B已经拿到的锁)
        $identifier = uniqid();

        while (!$this->redis->set($this->lockKey, $identifier, ['NX', 'EX' => $expire])) {
            // 如果设置失败,等待一段时间后重试
            usleep(1000);
        }

        return $identifier;
    }

    public function releaseLock($identifier)
    {
        // 释放锁,检查标识符是否匹配,确保只有持有锁的请求才能释放锁
        //这里的判断和删除锁需要保持原子性,所以使用Lua脚本来删除
        if ($this->redis->eval("if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end", [$this->lockKey, $identifier], 1)) {
            return true;
        }

        return false;
    }
}

// 示例用法
$lock = new RedisLock('my_resource');

// 尝试获取锁
$identifier = $lock->acquireLock();

if ($identifier) {
    // 成功获取锁,执行需要同步的操作

    // 释放锁
    $lock->releaseLock($identifier);
} else {
    // 获取锁失败,处理冲突或重试逻辑
    echo "Failed to acquire lock\n";
}
相关推荐
doubt。2 小时前
2.[网鼎杯 2020 朱雀组]phpweb
网络·安全·web安全·网络安全·php·代码复审
職場上的造物主2 小时前
高清种子资源获取指南 | ✈️@seedlinkbot
python·ios·php·音视频·视频编解码·视频
dal118网工任子仪2 小时前
94,【2】buuctf web [安洵杯 2019]easy_serialize_php
android·前端·php
飞火流星020275 小时前
docker安装Redis:docker离线安装Redis、docker在线安装Redis、Redis镜像下载、Redis配置、Redis命令
redis·docker·docker安装redis·redis镜像下载·redis基本操作·redis配置
lwprain5 小时前
springboot 2.7.6 security mysql redis jwt配置例子
spring boot·redis·mysql
yashunan5 小时前
Web_php_unserialize
android·前端·php
奥顺互联V6 小时前
yes镜像站群/PHP驱动的镜像站群架构实践
开发语言·架构·开源·php
如风暖阳7 小时前
Redis背景介绍
数据库·redis·缓存
lingllllove8 小时前
Redis脑裂问题详解及解决方案
数据库·redis·缓存
一张假钞8 小时前
Spark的基本概念
大数据·分布式·spark