PHP 使用 Redis 实现分布式锁

news2024/9/16 9:29:24

要在 PHP 中使用 Redis 实现分布式锁,可以使用类似的逻辑:通过 SET NX PX 命令获取锁,并通过唯一标识符(UUID)确保释放锁的正确性。以下是基于 PHP 的实现。

PHP 使用 Redis 实现分布式锁

1. 安装 Redis 扩展

在 PHP 中使用 Redis,你需要安装 phpredis 扩展。可以通过以下命令安装:

pecl install redis

安装完成后,确保在 php.ini 中启用了 Redis 扩展:

extension=redis.so
2. 实现分布式锁的 PHP 代码
<?php
class RedisLock {
    private $redis;
    private $lockKey;
    private $lockTimeout;
    private $identifier;

    public function __construct($host = '127.0.0.1', $port = 6379) {
        // 创建 Redis 连接
        $this->redis = new Redis();
        $this->redis->connect($host, $port);
    }

    /**
     * 获取分布式锁
     * @param string $lockKey 锁的键
     * @param int $acquireTimeout 获取锁的超时时间,超过该时间则放弃获取锁
     * @param int $lockTimeout 锁的过期时间(毫秒),防止死锁
     * @return string|false 成功获取锁时返回锁的唯一标识,失败时返回 false
     */
    public function acquireLock($lockKey, $acquireTimeout = 10000, $lockTimeout = 10000) {
        $this->lockKey = $lockKey;
        $this->lockTimeout = $lockTimeout;
        $this->identifier = uniqid();  // 生成唯一标识符

        $endTime = microtime(true) + $acquireTimeout / 1000;

        // 尝试获取锁,直至超时
        while (microtime(true) < $endTime) {
            // SET 锁,如果成功(NX:键不存在,PX:过期时间为毫秒)
            if ($this->redis->set($lockKey, $this->identifier, ['nx', 'px' => $lockTimeout])) {
                return $this->identifier;
            }
            usleep(10000); // 睡眠 10 毫秒后重试
        }

        return false;
    }

    /**
     * 释放分布式锁
     * @return bool 是否成功释放锁
     */
    public function releaseLock() {
        // 使用 Lua 脚本保证原子性操作:只有锁的拥有者才能释放锁
        $luaScript = '
            if redis.call("GET", KEYS[1]) == ARGV[1] then
                return redis.call("DEL", KEYS[1])
            else
                return 0
            end
        ';

        return $this->redis->eval($luaScript, [$this->lockKey, $this->identifier], 1);
    }
}

// 示例使用
$redisLock = new RedisLock();
$lockKey = 'my_distributed_lock';
$lockTimeout = 10000; // 锁的过期时间(10秒)

$lockIdentifier = $redisLock->acquireLock($lockKey, 5000, $lockTimeout); // 尝试 5 秒获取锁

if ($lockIdentifier) {
    try {
        // 获取锁成功,执行保护的业务逻辑
        echo "Lock acquired, executing business logic...\n";
        sleep(3); // 模拟业务处理
    } finally {
        // 释放锁
        $redisLock->releaseLock();
        echo "Lock released.\n";
    }
} else {
    echo "Failed to acquire lock.\n";
}
?>

3. PHP Redis 分布式锁的详细解释

  • 连接 Redis:通过 new Redis() 创建 Redis 客户端,并使用 connect() 方法连接到 Redis 服务。

  • 获取锁SET key value NX PX timeout 是获取锁的核心命令:

    • NX 表示仅当键不存在时才会设置键,确保只有一个客户端能获取锁。
    • PX 表示设置锁的过期时间(以毫秒为单位),避免死锁。
    • uniqid() 用来生成唯一标识符(identifier),确保每个客户端获取锁时的标识唯一。
  • 释放锁:使用 Lua 脚本来保证原子性操作,只有持有锁的客户端才可以释放锁。Lua 脚本的逻辑是:只有当 Redis 中存储的锁标识和当前客户端的标识相同时,才执行 DEL 操作删除锁。这样避免了因为竞争导致的锁被误删。

4. 关键点

  1. 死锁预防:通过设置锁的过期时间(PX 参数)避免死锁,即使客户端崩溃,锁也会在指定时间后自动释放。
  2. 唯一标识符:每个客户端在获取锁时都会生成一个唯一的标识符,这个标识符用于确保释放的锁是当前客户端的锁,防止误删除他人的锁。
  3. Lua 脚本:Redis 中的 Lua 脚本可以保证操作的原子性,确保释放锁时检查和删除是一个不可分割的操作。

5. Redis 锁的局限性

虽然 Redis 锁方案简单高效,但它有一些局限性:

  • 如果 Redis 集群有单点故障或者网络分区问题,可能会导致锁失效。
  • 适用于对锁可靠性要求不是特别高的场景,如果需要更高的可靠性,可以考虑使用 Redlock 算法 提高容错性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2116978.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx搭配gateway的集群配置

一、nginx在http里配置如下信息 upstream gateway-cluster {server 127.0.0.1:10001;server 127.0.0.1:10002;}server {listen 1000;server_name localhost;location ~/zzw_project/(.*) {proxy_pass http://gateway-cluster/$1;proxy_set_header Host $host; # 代理设…

延迟渲染路径

1. 延迟渲染路径处理光照的方式 延迟渲染路径对光照的数量没有任何限制&#xff0c;并且所有灯光都可以采用逐像素渲染。理论上来说&#xff0c;即 使场景中有成百上千个实时灯光&#xff0c;依然可以保持比较流畅的渲染帧率。它支持法线纹理、阴影等等效果的处理&#xff1b;…

【C++】STL容器详解【下】

目录 一、list容器 1.1 list基本概念 1.2 lsit构造函数 1.3 list数据元素插入和删除操作 1.4 list大小操作 1.5 list赋值操作 1.6 list数据的存取 1.7 list反转排序 二、set/multiset容器 2.1 set/multiset基本概念 2.2 set构造函数 2.3 set赋值操作 2.4 set大小操…

ChatGPT+Simple Mind Map生成思维导图:快速提升学习效率

一、告别杂乱笔记&#xff0c;一键生成清晰思维导图&#xff01; 最近开始学习网络安全&#xff0c;一头扎进了各种协议、漏洞、防御机制的海洋中。信息量巨大&#xff0c;知识点零散&#xff0c;让我很快便陷入了“知识焦虑”——笔记越记越多&#xff0c;却越来越混乱&#…

Django+Vue3前后端分离学习(二)(重写User类)

一、重写User类&#xff1a; 1、首先导入User类&#xff1a; from django.contrib.auth.models import User 2、然后点在User上&#xff0c;按住ctrl 点进去&#xff0c;发现 User类继承AbstractUser Ctrl点进去AbstractUser&#xff0c;然后将此方法全部复制到自己APP的mo…

基于微信小程序+Java+SSM+Vue+MySQL的宿舍管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSSMVueMySQL的宿舍管理系统【附源码文档…

UMI复现基础环境安装配置全流程(三)——UMI环境搭建

一、搭建UMI环境 &#xff08;二&#xff09;中安装了Anaconda3&#xff0c;在此基础上&#xff0c;创建umi环境&#xff0c;在universal_manipulation_interface-main文件夹中打开terminal并输入指令 conda env create -f conda_environment.yaml 此指令根据yaml文件创建环…

​数据编织+敏捷BI,打造企业智赢AI时代的双引擎丨直播预告

大数据产业创新服务媒体 ——聚焦数据 改变商业 随着数字化和智能化浪潮的不断推进&#xff0c;企业如何高效利用数据资源&#xff0c;成为了获取竞争优势的关键。在这样的背景下&#xff0c;我们诚邀您参加即将于2024年9月10日14:30开启的直播——“数据编织敏捷BI&#xff0…

实时通信利器:Web Broadcast Channel API 全面解读

一. 引言 在 Web 开发领域&#xff0c;实时通信一直是一个备受关注的话题。为了更好地实现实时消息传递和跨标签页通信&#xff0c;在 HTML5 规范中引入了 Web Broadcast Channel API。在本文中&#xff0c;我们将解析 Web Broadcast Channel API&#xff0c;探讨其用法以及相…

常见的正则化方法以及L1,L2正则化的简单描述

深度学习中的正则化是通过在模型训练过程中引入某些技术来防止模型过拟合的一种策略。过拟合是指模型在训练数据上表现非常好&#xff0c;但在新的、未见过的数据上表现不佳。正则化通过限制模型的复杂度或对模型参数施加约束&#xff0c;从而提高模型的泛化能力。 常见的正则…

【机器学习】高斯网络的基本概念和应用领域

引言 高斯网络&#xff08;Gaussian Network&#xff09;通常指的是一个概率图模型&#xff0c;其中所有的随机变量&#xff08;或节点&#xff09;都遵循高斯分布 文章目录 引言一、高斯网络&#xff08;Gaussian Network&#xff09;1.1 高斯过程&#xff08;Gaussian Proces…

Notepad++ 修改 About

1. 用这个工具&#xff0c;看标题&#xff0c;修改 1700 里的 Caption, 保存为 xx.exe, 2.修改链接&#xff0c;先准备如上。 2.1 使用插件 Hex Editor&#xff0c;拖入刚保存的 Notepad.exe 到 Notepad.exe, 按 c..S..H 2.2 按 ctrlf 查找 68 00 74 00 74 00 70 00 73 00 3…

ggplot作图基础

目录 ggplot作图语法 散点图 折线图 group分组 face_wrap()图像切片摆放 facet_grid()交叉分组切片 条形图 2.1 单组变量条形图 2.2 多维展示变量 直方图有与密度估计 直方图 密度估计图 ..density..语法和stat“density” ggplot作图语法 ggplot作图是将数据按需要进…

锡林郭勒奶酪品牌呼和浩特市大召店盛大开业

礼献中秋&#xff0c;香飘乳都。为进一步拓展锡林郭勒奶酪区域公用品牌产品销售渠道&#xff0c;9月8日&#xff0c;锡林郭勒奶酪区域公用品牌大召店在呼和浩特市大召广场月明楼隆重开业&#xff0c;现场为第三批新授权的39家奶酪生产经营主体代表授牌。至此&#xff0c;锡林郭…

Debian 12如何关闭防火墙

在Debian 12中&#xff0c;默认的防火墙管理工具是ufw&#xff08;Uncomplicated Firewall&#xff09;。您可以使用以下命令来关闭防火墙&#xff1a; 关闭防火墙&#xff1a; sudo ufw disable查看防火墙状态&#xff1a; sudo ufw status如果需要重新开启防火墙&#xff1a;…

9.8javaweb项目总结

1.主界面用户信息显示 登录成功后&#xff0c;将用户信息存储在记录在 localStorage中&#xff0c;然后进入界面之前通过js来渲染主界面 存储用户信息 将用户信息渲染在主界面上&#xff0c;并且头像设置跳转&#xff0c;到个人资料界面 这里数据库中还没有设置相关信息 2.模糊…

数学建模笔记—— 主成分分析(PCA)

数学建模笔记—— 主成分分析 主成分分析1. 基本原理1.1 主成分分析方法1.2 数据降维1.3 主成分分析原理1.4 主成分分析思想 2. PCA的计算步骤3. 典型例题4. 主成分分析说明5. python代码实现 主成分分析 1. 基本原理 在实际问题研究中,多变量问题是经常会遇到的。变量太多,无…

通信工程学习:什么是PSK相移键控、2PSK/BPSK二进制相移键控

PSK相移键控、2PSK/BPSK二进制相移键控 PSK&#xff08;相移键控&#xff09;和2PSK/BPSK&#xff08;二进制相移键控&#xff09;是两种在通信系统中广泛使用的调制技术。以下是对它们的详细解释&#xff1a; 一、PSK&#xff1a;相移键控 1、PSK相移键控的定义&#xff1a;…

websocket client无法连接到websocket server 的问题

1. 问题描述 生产环境的websocket client和server无法通信 2. 日志现象 通过查看日志和问题复现&#xff0c;定位到是client连接到server失败&#xff0c;导致无法通信。 出现问题的代码 出现问题的日志 21:25:27.790 [main] INFO websocket.MyWebSocketClient - start to…

力扣第347题 前K个高频元素

前言 记录一下刷题历程 力扣第347题 前K个高频元素 前K个高频元素 原题目&#xff1a; 分析 我们首先使用哈希表来统计数字出现的频率&#xff0c;然后我们使用一个桶排序。我们首先定义一个长度为n1的数组&#xff0c;对于下图这个示例就是长度为7的数组。为什么需要一个长…