原代码:https://github.com/ronnylt/redlock-php
“优化”后的代码:
/** * redis锁 */ class RedisLock { /** @var int $retryDelay */ private $retryDelay; /** @var int $retryCount */ private $retryCount; /** @var float $clockDriftFactor */ private $clockDriftFactor = 0.01; /** @var \Redis */ private $redis; /** * RedisLock constructor. * @param \Redis $redis * @param int $retryDelay * @param int $retryCount */ function __construct($redis, $retryDelay = 200, $retryCount = 3) { $this->redis = $redis; $this->retryDelay = $retryDelay; $this->retryCount = $retryCount; } /** * @param string $resource * @param int $ttl 单位:毫秒 * @return array|bool 返回钥匙信息 */ public function lock($resource, $ttl = 5000) { $token = uniqid(); $retry = $this->retryCount; do { $startTime = microtime(true) * 1000; if (!$this->lockInstance($this->redis, $resource, $token, $ttl)) { return false; } $drift = ($ttl * $this->clockDriftFactor) + 2; $validityTime = $ttl - (microtime(true) * 1000 - $startTime) - $drift; if ($validityTime > 0) { return [ 'validity' => $validityTime, 'resource' => $resource, 'token' => $token, ]; } else { $this->unlockInstance($this->redis, $resource, $token); } $delay = mt_rand(floor($this->retryDelay / 2), $this->retryDelay); usleep($delay * 1000); $retry--; } while ($retry > 0); return false; } /** * 参数是钥匙信息 * * @param array $lock */ public function unlock(array $lock) { $resource = $lock['resource']; $token = $lock['token']; $this->unlockInstance($this->redis, $resource, $token); } private function lockInstance($instance, $resource, $token, $ttl) { return $instance->set($resource, $token, ['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, [$resource, $token], 1); } }