当前位置:首页 > 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 命令支持更多选项,可以实现更安全的锁机制:

$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 实例上获取锁:

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 客户端库,可以这样实现:

php实现redis锁

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 实现打印功能的方法 PHP 可以通过多种方式实现打印功能,具体取决于打印的目标(如打印机、PDF、网页等)和需求(如直接打印、生成打印预览等)。以下是几种常见的实现方式: 使用 JavaSc…

php记住密码怎么实现

php记住密码怎么实现

使用Cookie实现记住密码功能 在PHP中,可以通过设置Cookie来记住用户的登录状态。以下是一个简单的实现方式: // 用户登录验证成功后 if ($login_success) {…

php长连接实现

php长连接实现

PHP 长连接实现方法 长连接(Keep-Alive)允许客户端与服务器在一次TCP连接中发送和接收多个HTTP请求/响应,减少重复建立连接的开销。以下是PHP中实现长连接的几种方式: 配置HTTP…

php 实现购物车

php 实现购物车

PHP 实现购物车功能 购物车功能是电子商务网站的核心部分,可以通过 PHP 和 Session 或数据库来实现。以下是两种常见的实现方式: 使用 Session 存储购物车数据 Sessi…

php实现推送

php实现推送

PHP 实现推送功能的方法 PHP 实现推送功能可以通过多种方式完成,包括 WebSocket、Server-Sent Events (SSE)、长轮询或第三方推送服务。以下是几种常见的方法: 使用…

php 实现无限分类

php 实现无限分类

无限分类的实现方法 无限分类通常用于构建多层级结构的数据,如商品分类、菜单管理等。以下是几种常见的实现方式: 邻接列表模型(Adjacency List) 这是最简单的实现方式,每个分类记录存储其父…