当前位置:首页 > PHP

php实现redis锁

2026-02-16 03:29:12PHP

PHP 实现 Redis 锁的方法

使用 SETNX 命令实现基本锁

在 PHP 中可以通过 Redis 的 SETNX 命令实现简单的分布式锁。SETNX 是 "SET if Not eXists" 的缩写,只有当键不存在时才会设置值。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$lockKey = 'resource_lock';
$lockExpire = 10; // 锁过期时间(秒)

// 尝试获取锁
$isLocked = $redis->setnx($lockKey, time() + $lockExpire);

if (!$isLocked) {
    // 检查锁是否过期
    $lockTime = $redis->get($lockKey);
    if (time() > $lockTime) {
        // 锁已过期,删除并重新获取
        $redis->del($lockKey);
        $isLocked = $redis->setnx($lockKey, time() + $lockExpire);
    }
}

if ($isLocked) {
    try {
        // 执行业务代码
    } finally {
        // 释放锁
        $redis->del($lockKey);
    }
} else {
    // 获取锁失败
}

使用 SET 命令带选项实现更安全的锁

Redis 2.6.12 之后,SET 命令支持更多选项,可以实现更安全的锁机制:

php实现redis锁

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$lockKey = 'resource_lock';
$lockExpire = 10; // 锁过期时间(秒)
$lockToken = uniqid(); // 唯一标识符

// 尝试获取锁
$isLocked = $redis->set(
    $lockKey, 
    $lockToken, 
    ['nx', 'ex' => $lockExpire]
);

if ($isLocked) {
    try {
        // 执行业务代码
    } finally {
        // 确保只释放自己的锁
        if ($redis->get($lockKey) === $lockToken) {
            $redis->del($lockKey);
        }
    }
} else {
    // 获取锁失败
}

使用 RedLock 算法实现分布式锁

对于更复杂的分布式环境,可以使用 RedLock 算法,它需要在多个独立的 Redis 实例上获取锁:

php实现redis锁

function acquireLock($redisInstances, $resource, $ttl, $retryCount = 3, $retryDelay = 200) {
    $token = uniqid();
    $lockSuccessCount = 0;

    for ($i = 0; $i < $retryCount; $i++) {
        $lockSuccessCount = 0;

        foreach ($redisInstances as $redis) {
            if ($redis->set($resource, $token, ['nx', 'px' => $ttl])) {
                $lockSuccessCount++;
            }
        }

        // 检查是否在大多数实例上获取了锁
        if ($lockSuccessCount > (count($redisInstances) / 2)) {
            return $token;
        }

        // 释放已经获取的锁
        foreach ($redisInstances as $redis) {
            $redis->del($resource);
        }

        usleep($retryDelay * 1000);
    }

    return false;
}

function releaseLock($redisInstances, $resource, $token) {
    foreach ($redisInstances as $redis) {
        $script = '
            if redis.call("get", KEYS[1]) == ARGV[1] then
                return redis.call("del", KEYS[1])
            else
                return 0
            end
        ';
        $redis->eval($script, [$resource, $token], 1);
    }
}

使用 Redis 扩展的锁功能

某些 PHP Redis 扩展(如 phpredis)提供了内置的锁方法:

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

if ($redis->rawCommand('LOCK', 'my_lock', 'NX', 'EX', 10)) {
    try {
        // 执行业务代码
    } finally {
        $redis->rawCommand('UNLOCK', 'my_lock');
    }
}

使用 Predis 库实现 Redis 锁

如果使用 Predis 客户端库,可以这样实现:

require 'vendor/autoload.php';
$client = new Predis\Client();

$lockKey = 'resource_lock';
$lockExpire = 10;
$lockToken = uniqid();

$lockAcquired = $client->set($lockKey, $lockToken, 'EX', $lockExpire, 'NX');

if ($lockAcquired) {
    try {
        // 执行业务代码
    } finally {
        $script = '
            if redis.call("get", KEYS[1]) == ARGV[1] then
                return redis.call("del", KEYS[1])
            else
                return 0
            end
        ';
        $client->eval($script, 1, $lockKey, $lockToken);
    }
}

注意事项

  • 确保为锁设置合理的过期时间,避免死锁
  • 使用唯一标识符(token)来确保只释放自己的锁
  • 考虑锁续期机制,如果业务执行时间可能超过锁的过期时间
  • 在高并发环境下,重试机制和退避策略很重要
  • 分布式环境下,时钟同步问题需要考虑
  • 评估业务对锁的需求强度,有些场景可能不需要强一致性锁

标签: phpredis
分享给朋友:

相关文章

php 实现文件下载

php 实现文件下载

实现文件下载的基本方法 使用 PHP 实现文件下载的核心是通过设置 HTTP 头部信息,强制浏览器将文件作为附件下载而非直接显示。以下是一个基础实现示例: $file_path = '/path/t…

php无限分类的实现

php无限分类的实现

PHP无限分类的实现 无限分类是一种常见的树形结构数据组织方式,适用于商品分类、菜单管理、地区选择等场景。以下是几种实现方法: 递归实现法 递归是最直观的实现方式,通过函数自身调用来遍历子分类。数据…

php搜索功能实现的

php搜索功能实现的

PHP 搜索功能实现方法 数据库搜索实现 使用 SQL 的 LIKE 语句进行模糊匹配,适用于小型网站和简单搜索需求。 $searchTerm = $_GET['search']; $query =…

php实现域名

php实现域名

PHP实现域名操作的方法 获取当前域名 使用$_SERVER['HTTP_HOST']可以获取当前访问的域名: $currentDomain = $_SERVER['HTTP_HOST']; ech…

php 实现链表

php 实现链表

PHP 实现链表的方法 链表是一种线性数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针。PHP 中可以通过类和对象来实现链表。 定义链表节点类 创建一个 ListNode 类,用于表示链…

php session实现购物车

php session实现购物车

PHP Session 实现购物车 初始化 Session 确保在使用 Session 前调用 session_start() 函数。通常放在 PHP 文件的最顶部。 <?php sessio…