php 使用redis鎖限制并發(fā)訪問類示例
本文介紹了php 使用redis鎖限制并發(fā)訪問類,并詳細(xì)的介紹了并發(fā)訪問限制方法。
1.并發(fā)訪問限制問題
對于一些需要限制同一個(gè)用戶并發(fā)訪問的場景,如果用戶并發(fā)請求多次,而服務(wù)器處理沒有加鎖限制,用戶則可以多次請求成功。
例如換領(lǐng)優(yōu)惠券,如果用戶同一時(shí)間并發(fā)提交換領(lǐng)碼,在沒有加鎖限制的情況下,用戶則可以使用同一個(gè)換領(lǐng)碼同時(shí)兌換到多張優(yōu)惠券。
偽代碼如下:
if A(可以換領(lǐng))
B(執(zhí)行換領(lǐng))
C(更新為已換領(lǐng))
D(結(jié)束)
如果用戶并發(fā)提交換領(lǐng)碼,都能通過可以換領(lǐng)(A)的判斷,因?yàn)楸仨氂幸粋€(gè)執(zhí)行換領(lǐng)(B)后,才會更新為已換領(lǐng)(C)。因此如果用戶在有一個(gè)更新為已換領(lǐng)之前,有多少次請求,這些請求都可以執(zhí)行成功。
2.并發(fā)訪問限制方法
使用文件鎖可以實(shí)現(xiàn)并發(fā)訪問限制,但對于分布式架構(gòu)的環(huán)境,使用文件鎖不能保證多臺服務(wù)器的并發(fā)訪問限制。
Redis是一個(gè)開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。
本文將使用其setnx方法實(shí)現(xiàn)分布式鎖功能。setnx即Set it N**ot eX**ists。
當(dāng)鍵值不存在時(shí),插入成功(獲取鎖成功),如果鍵值已經(jīng)存在,則插入失?。ǐ@取鎖失?。?/p>
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連接設(shè)定 */ public function __construct($config=array()){ $this->_config = $config; $this->_redis = $this->connect(); } /** * 獲取鎖 * @param String $key 鎖標(biāo)識 * @param Int $expire 鎖過期時(shí)間 * @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 鎖標(biāo)識 * @return Boolean */ public function unlock($key){ return $this->_redis->del($key); } /** * 創(chuàng)建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, ); // 創(chuàng)建redislock對象 $oRedisLock = new RedisLock($config); // 定義鎖標(biāo)識 $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>'; } ?>
測試方法:
打開兩個(gè)不同的瀏覽器,同時(shí)在A,B中訪問demo.php
如果先訪問的會獲取到鎖
輸出
get lock success
do sth..
success
另一個(gè)獲取鎖失敗則會輸出request too frequently
保證同一時(shí)間只有一個(gè)訪問有效,有效限制并發(fā)訪問。
為了避免系統(tǒng)突然出錯(cuò)導(dǎo)致死鎖,所以在獲取鎖的時(shí)候增加一個(gè)過期時(shí)間,如果已超過過期時(shí)間,即使是鎖定狀態(tài)都會釋放鎖,避免死鎖導(dǎo)致的問題。
源碼下載地址:點(diǎn)擊查看
相關(guān)文章
php使用ffmpeg獲取視頻信息并截圖的實(shí)現(xiàn)方法
這篇文章主要介紹了php使用ffmpeg獲取視頻信息并截圖的實(shí)現(xiàn)方法,實(shí)例分析了php操作視頻與圖像的相關(guān)技巧,需要的朋友可以參考下2016-05-05PHP封裝XML和JSON格式數(shù)據(jù)接口操作示例
這篇文章主要介紹了PHP封裝XML和JSON格式數(shù)據(jù)接口操作,結(jié)合實(shí)例形式分析了php針對xml與json格式數(shù)據(jù)接口封裝相關(guān)操作技巧,需要的朋友可以參考下2019-03-03php目錄遍歷函數(shù)opendir用法實(shí)例
這篇文章主要介紹了php目錄遍歷函數(shù)opendir用法,以實(shí)例形式詳細(xì)分析了opendir原理與用法,是PHP進(jìn)行目錄操作的一個(gè)重要函數(shù),需要的朋友可以參考下2014-11-11PHP Parser 掃描應(yīng)用打印輸出結(jié)構(gòu)語句實(shí)例
這篇文章主要為大家介紹了PHP Parser 掃描應(yīng)用打印輸出結(jié)構(gòu)語句實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09