首页 > 数据库 >Redis 锁的使用

Redis 锁的使用

时间:2022-11-25 12:05:29浏览次数:33  
标签:resource redis Redis private instance token 使用 array


<?php

/**
* Redis distributed locks in PHP
* @author assasin <>
*/
class RedisLock {

private $retryDelay;
private $retryCount;
private $clockDriftFactor = 0.01;
private $quorum;
private $servers = array();
private $instances = array();

/**
* Redis default prefix
* @var string
*/
public $prefix = "";

/**
* The database to use, defaults to 1
* @var integer
*/
public $database = 1;

public function __construct(array $servers = array(array('127.0.0.1', 6379, 0.01)), $retryDelay = 200, $retryCount = 3) {
$this->servers = $servers;

$this->retryDelay = $retryDelay;
$this->retryCount = $retryCount;

$this->quorum = min(count($servers), (count($servers) / 2 + 1));
}

public function lock($resource, $ttl) {
$this->initInstances();

$token = uniqid();
$retry = $this->retryCount;

do {
$n = 0;

$startTime = microtime(true) * 1000;

foreach ($this->instances as $instance) {
if ($this->lockInstance($instance, $resource, $token, $ttl)) {
$n++;
}
}

# Add 2 milliseconds to the drift to account for Redis expires
# precision, which is 1 millisecond, plus 1 millisecond min drift
# for small TTLs.
$drift = ($ttl * $this->clockDriftFactor) + 2;

$validityTime = $ttl - (microtime(true) * 1000 - $startTime) - $drift;

if ($n >= $this->quorum && $validityTime > 0) {
return array(
'validity' => $validityTime,
'resource' => $resource,
'token' => $token,
);
} else {
foreach ($this->instances as $instance) {
$this->unlockInstance($instance, $resource, $token);
}
}

// Wait a random delay before to retry
$delay = mt_rand(floor($this->retryDelay / 2), $this->retryDelay);
usleep($delay * 1000);

$retry--;
} while ($retry > 0);

return false;
}

public function unlock(array $lock) {
$this->initInstances();
$resource = $lock['resource'];
$token = $lock['token'];

foreach ($this->instances as $instance) {
$this->unlockInstance($instance, $resource, $token);
}
}

private function initInstances() {
if (empty($this->instances)) {
foreach ($this->servers as $server) {
list($host, $port, $timeout) = $server;
$redis = new \Redis();
if ($redis->connect($host, $port, $timeout) === false) {
continue;
}
$redis->setOption(Redis::OPT_PREFIX, $this->prefix);
$redis->select($this->database);

$this->instances[] = $redis;
}
}
}

private function lockInstance($instance, $resource, $token, $ttl) {
return $instance->set($resource, $token, array('NX', 'PX' => $ttl));
}

private function unlockInstance($instance, $resource, $token) {
$script = '
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
';
return $instance->eval($script, array($resource, $token), 1);
}

}

标签:resource,redis,Redis,private,instance,token,使用,array
From: https://blog.51cto.com/u_13940603/5886200

相关文章