동일한 사용자의 동시 접속을 제한해야 하는 일부 시나리오의 경우 사용자는 동시 요청 횟수가 많고 서버 처리에 대한 잠금 제한이 없으며 사용자는 여러 번 성공적으로 요청할 수 있습니다.
예를 들어 쿠폰 사용 시 사용자가 동시에 사용 코드를 제출하면 동일한 사용 코드를 사용하여 잠금 제한 없이 동시에 여러 쿠폰을 사용할 수 있습니다.
의사 코드는 다음과 같습니다.
if A(可以换领) B(执行换领) C(更新为已换领)D(结束)
사용자가 상환 코드를 동시에 제출하면 모두 상환 가능(A) 판정을 통과할 수 있습니다. 구속(B)을 수행하는 사람이 되면 구속(C)으로 업데이트됩니다. 따라서 업데이트가 회수되기 전에 사용자가 여러 요청을 하면 해당 요청이 성공적으로 실행될 수 있습니다.
파일 잠금을 사용하면 동시 접근 제한이 가능하지만, 분산 아키텍처 환경에서는 파일 잠금을 사용하면 여러 서버의 보안을 보장할 수 없습니다. 동시 액세스 제한.
Redis는 ANSI C 언어로 작성된 오픈소스 로그형 Key-Value 데이터베이스로, 네트워크를 지원하고, 메모리 기반 및 영속성이 있으며, 다국어로 API를 제공합니다.
이 기사에서는 setnx 메소드를 사용하여 분산 잠금 기능을 구현합니다. setnx는 SetNX하지 않습니다.
키 값이 없으면 삽입 성공(잠금 획득 성공) 키 값이 이미 있으면 삽입 실패(잠금 획득 실패)
RedisLock.class.php
<?php/** * Redis锁操作类 * Date: 2016-06-30 * Author: fdipzone * Ver: 1.0 * * Func: * public lock 获取锁 * public unlock 释放锁 * private connect 连接 */class RedisLock { // class start private $_config; private $_redis; /** * 初始化 * @param Array $config redis连接设定 */ public function __construct($config=array()){ $this->_config = $config; $this->_redis = $this->connect(); } /** * 获取锁 * @param String $key 锁标识 * @param Int $expire 锁过期时间 * @return Boolean */ public function lock($key, $expire=5){ $is_lock = $this->_redis->setnx($key, time()+$expire); // 不能获取锁 if(!$is_lock){ // 判断锁是否过期 $lock_time = $this->_redis->get($key); // 锁已过期,删除锁,重新获取 if(time()>$lock_time){ $this->unlock($key); $is_lock = $this->_redis->setnx($key, time()+$expire); } } return $is_lock? true : false; } /** * 释放锁 * @param String $key 锁标识 * @return Boolean */ public function unlock($key){ return $this->_redis->del($key); } /** * 创建redis连接 * @return Link */ private function connect(){ try{ $redis = new Redis(); $redis->connect($this->_config['host'], $this->_config['port'],$this->_config['timeout'], $this->_config['reserved'],$this->_config['retry_interval']); if(empty($this->_config['auth'])){ $redis->auth($this->_config['auth']); } $redis->select($this->_config['index']); }catch(RedisException $e){ throw new Exception($e->getMessage()); return false; } return $redis; } } // class end?>
demo.php
<?php require 'RedisLock.class.php'; $config = array( 'host' => 'localhost', 'port' => 6379, 'index' => 0, 'auth' => '', 'timeout' => 1, 'reserved' => NULL, 'retry_interval' => 100, ); // 创建redislock对象$oRedisLock = new RedisLock($config); // 定义锁标识$key = 'mylock'; // 获取锁$is_lock = $oRedisLock->lock($key, 10); if($is_lock){ echo 'get lock success<br>'; echo 'do sth..<br>'; sleep(5); echo 'success<br>'; $oRedisLock->unlock($key); // 获取锁失败 } else{ echo 'request too frequently<br>'; }?>
테스트 방법:
두 개의 다른 브라우저를 열고 A와 B에서 동시에 데모.php에 액세스합니다.
먼저 액세스하면 잠금을 얻습니다.
출력
잠금 성공
do sth.
success
다른 사람이 잠금을 획득하지 못하면 너무 자주 요청
이 출력됩니다. 동시에 하나의 액세스만 유효하도록 하여 동시 액세스를 효과적으로 제한합니다.
갑작스러운 시스템 오류로 인한 교착 상태를 방지하기 위해 잠금 획득 시 만료 시간을 추가합니다. 만료 시간이 지나면 잠금 상태에서도 잠금이 해제됩니다. 교착상태 문제를 피하기 위해.
소스코드 다운로드 주소 : 클릭하시면 보실 수 있습니다
필요한 일부 사용자의 경우 동시성 제한 액세스 시나리오에서 사용자가 여러 개의 동시 요청을 하고 서버 프로세스에 잠금 제한이 없으면 사용자는 여러 개의 성공적인 요청을 할 수 있습니다.
예를 들어 쿠폰 사용 시 사용자가 동시에 사용 코드를 제출하면 동일한 사용 코드를 사용하여 잠금 제한 없이 동시에 여러 쿠폰을 사용할 수 있습니다.
의사 코드는 다음과 같습니다.
if A(可以换领) B(执行换领) C(更新为已换领)D(结束)
사용자가 상환 코드를 동시에 제출하면 모두 상환 가능(A) 판정을 통과할 수 있습니다. 구속(B)을 수행하는 사람이 되면 구속(C)으로 업데이트됩니다. 따라서 업데이트가 회수되기 전에 사용자가 여러 요청을 하면 해당 요청이 성공적으로 실행될 수 있습니다.
파일 잠금을 사용하면 동시 접근 제한이 가능하지만, 분산 아키텍처 환경에서는 파일 잠금을 사용하면 여러 서버의 보안을 보장할 수 없습니다. 동시 액세스 제한.
Redis는 ANSI C 언어로 작성된 오픈소스 로그형 Key-Value 데이터베이스로, 네트워크를 지원하고, 메모리 기반 및 영속성이 있으며, 다국어로 API를 제공합니다.
이 기사에서는 setnx 메소드를 사용하여 분산 잠금 기능을 구현합니다. setnx는 SetNX하지 않습니다.
키 값이 없으면 삽입 성공(잠금 획득 성공) 키 값이 이미 있으면 삽입 실패(잠금 획득 실패)
RedisLock.class.php
<?php/** * Redis锁操作类 * Date: 2016-06-30 * Author: fdipzone * Ver: 1.0 * * Func: * public lock 获取锁 * public unlock 释放锁 * private connect 连接 */class RedisLock { // class start private $_config; private $_redis; /** * 初始化 * @param Array $config redis连接设定 */ public function __construct($config=array()){ $this->_config = $config; $this->_redis = $this->connect(); } /** * 获取锁 * @param String $key 锁标识 * @param Int $expire 锁过期时间 * @return Boolean */ public function lock($key, $expire=5){ $is_lock = $this->_redis->setnx($key, time()+$expire); // 不能获取锁 if(!$is_lock){ // 判断锁是否过期 $lock_time = $this->_redis->get($key); // 锁已过期,删除锁,重新获取 if(time()>$lock_time){ $this->unlock($key); $is_lock = $this->_redis->setnx($key, time()+$expire); } } return $is_lock? true : false; } /** * 释放锁 * @param String $key 锁标识 * @return Boolean */ public function unlock($key){ return $this->_redis->del($key); } /** * 创建redis连接 * @return Link */ private function connect(){ try{ $redis = new Redis(); $redis->connect($this->_config['host'], $this->_config['port'], $this->_config['timeout'], $this->_config['reserved'], $this->_config['retry_interval']); if(empty($this->_config['auth'])){ $redis->auth($this->_config['auth']); } $redis->select($this->_config['index']); }catch(RedisException $e){ throw new Exception($e->getMessage()); return false; } return $redis; } } // class end?>
demo.php
<?phprequire 'RedisLock.class.php'; $config = array( 'host' => 'localhost', 'port' => 6379, 'index' => 0, 'auth' => '', 'timeout' => 1, 'reserved' => NULL, 'retry_interval' => 100, ); // 创建redislock对象$oRedisLock = new RedisLock($config); // 定义锁标识$key = 'mylock'; // 获取锁$is_lock = $oRedisLock->lock($key, 10); if($is_lock){ echo 'get lock success<br>'; echo 'do sth..<br>'; sleep(5); echo 'success<br>'; $oRedisLock->unlock($key); // 获取锁失败 } else{ echo 'request too frequently<br>'; }?>
테스트 방법:
두 개의 다른 브라우저를 열고 A와 B에서 동시에 데모.php에 액세스합니다.
먼저 액세스하면 잠금을 얻습니다.
출력
잠금 성공
do sth.
success
다른 사람이 잠금을 획득하지 못하면 너무 자주 요청
이 출력됩니다. 동시에 하나의 액세스만 유효하도록 하여 동시 액세스를 효과적으로 제한합니다.
갑작스러운 시스템 오류로 인한 교착 상태를 방지하기 위해 잠금 획득 시 만료 시간을 추가합니다. 만료 시간이 지나면 잠금 상태에서도 잠금이 해제됩니다. 교착상태 문제를 피하기 위해.
위 내용은 redis lock을 사용하여 동시 접속을 제한하는 PHP 내용이며, 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php)를 참고하시기 바랍니다. .cn)!