PHP+Redis实现分布式锁
<?php
// 引入Predis客户端
require 'vendor/autoload.php';
use Predis\Client;
class RedisLock {
private $redis;
private $lockKey;
private $timeout = 5; // 锁的超时时间,单位秒
public function __construct($redisHost, $redisPort, $lockKey) {
$this->redis = new Client(array(
'scheme' => 'tcp',
'host' => $redisHost,
'port' => $redisPort,
));
$this->lockKey = $lockKey;
}
// 获取锁
public function acquireLock() {
$expireTime = time() + $this->timeout;
$lockKey = $this->lockKey . "_lock";
// 使用SET命令的NX选项来实现分布式锁
// PX选项用于设置锁的过期时间
$result = $this->redis->set($lockKey, $expireTime, 'NX', 'PX', $this->timeout * 1000);
return $result ? true : false;
}
// 释放锁
public function releaseLock() {
$lockKey = $this->lockKey . "_lock";
// 获取锁的过期时间
$expireTime = $this->redis->get($lockKey);
// 检查锁是否存在,并且是由当前客户端持有的
if ($expireTime && time() < $expireTime) {
// 使用Lua脚本来原子化地检查并删除锁
$script = '
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
';
$result = $this->redis->eval($script, 1, $lockKey, $expireTime);
return $result ? true : false;
}
return false;
}
}
// 使用示例
$lock = new RedisLock('127.0.0.1', 6379, 'my_lock_key');
if ($lock->acquireLock()) {
// 执行需要互斥的操作
echo "Lock acquired. Doing some work...\n";
// 模拟工作
sleep(10);
// 完成工作后释放锁
if ($lock->releaseLock()) {
echo "Lock released.\n";
} else {
echo "Failed to release lock.\n";
}
} else {
echo "Failed to acquire lock.\n";
}
?>
这段代码使用了Redis的SET命令的NX和PX选项来实现分布式锁。NX选项确保只有在键不存在的情况下才会设置键,PX选项用于设置键的过期时间。在释放锁时,使用Lua脚本来原子化地检查键的值并删除键,以此来确保锁只会被持有它的客户端所释放。
评论已关闭