概要:
- 認識Redis的本質:設計目標,應用場景
- 理解爲Redis的工做模式
- 認識Redis計數器
- 如何用Redis計數器實現併發場景下的數量控制
- Redis是什麼
- 緩存
- 數據庫
- 消息代理
- Redis和Memcache對比
- Memcache是內存對象緩存系統,設計目標爲了經過緩解數據庫的壓力來加快web應用的響應速度
- Redis應用場景更豐富,Memcache僅適合做爲緩存使用
- Redis的工做模式
- 單進程(僅有一個進程處理請求)
- 阻塞式(處理請求時具備原子性)
- Memcache與之相反,多進程非阻塞式
- Redis優缺點
- 優勢:無需處理併發問題,下降系統複雜度
- 缺點:不適合緩存大尺寸對象(100KB 可修改配置)
- Redis計數器
- 存儲類型:整數型String
- 應用場景
- 頻率控制
- 接口防刷(key爲IP地址,value爲訪問次數,key生成時間可設置爲1s)
- 密碼嘗試次數限制(防止密碼被暴力破解)
- 數量統計:請求量統計(相似頻率控制)
- 數量控制:商品搶購,獎勵額度控制
- 涉及命令
- exists key //檢查key是否存在
- setnx key value //當key不存在時進行set操做
- expire key seconds //設置key的生存時間,沒有ttl返回-1,過時返回-2
- ttl ksy //查看key的生存時間
- Redis數量控制器
- 應用場景
- 商品搶購,庫存發生超買超賣
- 抽獎限量
- 搶紅包
- ...
- 抽獎限額場景v1版本流程圖
- 抽獎限額場景v2版本流程圖
- 抽獎限額源碼
1 <?php 2 require_once('vender/autoload.php');//引入自動加載類 3 use Predis\Client;//引入Predis包 4 5 //獲取計數器名稱 6 function getKeyName($v){ 7 return "mycounter_".$v; 8 } 9 //生成redis客戶端 10 function getRedisClient(){ 11 return new Client([ 12 'host'=>'127.0.0.1', 13 'port'=>'6379' 14 ]); 15 } 16 //記錄中獎日誌 17 function writeLog($msg, $v){ 18 $log = $msg.PHP_EOL; 19 file_put_contents("log/$v.log", $log, FILE_APPEND); 20 } 21 //v1版本計數器 22 function v1(){ 23 $amountLimit = 100;//獎金總額100 24 $keyName = getKeyName('v1');//獲取計數器名稱 25 $redis = getRedisClient();//獲取redis客戶端 26 $incrAmount = 1;//增長額,假定每一個用戶的增長額爲1 27 //判斷key是否存在 28 if(!$redis->exists($keyName)){ 29 $redi->set($keyName,95);//不存在,假定初始化爲95 30 } 31 $currAmount = $redis->get($keyName);//獲取當前已發放的獎勵額度 32 //判斷當前量+增長量是否>獎勵限額 33 if($currAmount + $incrAmount > $amountLimit){ 34 writeLog('未中獎', 'v1'); 35 return; 36 } 37 $redis->incrby($keyName, $incrAmount); 38 writeLog('中獎', 'v1'); 39 } 40 //v2版本計數器 41 function v2(){ 42 $amountLimit = 100;//獎金總額100 43 $keyName = getKeyName('v2');//獲取計數器名稱 44 $redis = getRedisClient();//獲取redis客戶端 45 $incrAmount = 1;//增長額,假定每一個用戶的增長額爲1 46 //判斷key是否存在 47 if(!$redis->exists($keyName)){ 48 $redi->set($keyName,95);//不存在,假定初始化已發放爲95 49 } 50 //判斷增長額度後返回值是否>獎勵限額 51 if($redis->incrby($keyName, $incrAmount) > $amountLimit){ 52 writeLog('未中獎', 'v2'); 53 return; 54 } 55 writeLog('中獎', 'v2'); 56 } 57 58 if($_GET['v'] == 2){ 59 v2(); 60 }else{ 61 v1(); 62 }
- 併發測試
- 使用ab進行壓力測試
- ab -c 100 -n 200 http://redis.limitation.test?v=2 //併發數100,請求數200
- less -N log/v2.log //查看日誌,檢查結果的正確性