溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

php中怎么實(shí)現(xiàn)redis分布式鎖

發(fā)布時(shí)間:2021-06-29 17:13:57 來源:億速云 閱讀:336 作者:Leah 欄目:編程語言

這篇文章給大家介紹php中怎么實(shí)現(xiàn)redis分布式鎖,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

前言

分布式鎖一般有三種實(shí)現(xiàn)方式:

1. 數(shù)據(jù)庫樂觀鎖;2. 基于Redis的分布式鎖;3. 基于ZooKeeper的分布式鎖。

可靠性

首先,為了確保分布式鎖可用,我們至少要確保鎖的實(shí)現(xiàn)同時(shí)滿足以下四個(gè)條件:

  1. 互斥性。在任意時(shí)刻,只有一個(gè)客戶端能持有鎖。

  2. 不會(huì)發(fā)生死鎖。即使有一個(gè)客戶端在持有鎖的期間崩潰而沒有主動(dòng)解鎖,也能保證后續(xù)其他客戶端能加鎖。

  3. 具有容錯(cuò)性。只要大部分的Redis節(jié)點(diǎn)正常運(yùn)行,客戶端就可以加鎖和解鎖。

  4. 解鈴還須系鈴人。加鎖和解鎖必須是同一個(gè)客戶端,客戶端自己不能把別人加的鎖給解了

代碼實(shí)現(xiàn)

<?phpclass RedLock{private $retryDelay;private $retryCount;private $clockDriftFactor = 0.01;private $quorum;private $servers = array();private $instances = array();function __construct(array $servers, $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 ['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();$redis->connect($host, $port, $timeout);$this->instances[] = $redis;}}}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);}}

使用示例

<?phprequire_once __DIR__ . '/../src/RedLock.php';$servers = [['127.0.0.1', 6379, 0.01],['127.0.0.1', 6389, 0.01],['127.0.0.1', 6399, 0.01],];$redLock = new RedLock($servers);while (true) {$lock = $redLock->lock('test', 10000);if ($lock) {print_r($lock);} else {print "Lock not acquired\n";}}

關(guān)于php中怎么實(shí)現(xiàn)redis分布式鎖就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI