Redis計數器與數量控制

概要:
  1. 認識Redis的本質:設計目標,應用場景
  2. 理解爲Redis的工做模式
  3. 認識Redis計數器
  4. 如何用Redis計數器實現併發場景下的數量控制
 
 
  1. Redis是什麼
    1. 緩存
    2. 數據庫
    3. 消息代理
  2. Redis和Memcache對比
    1. Memcache是內存對象緩存系統,設計目標爲了經過緩解數據庫的壓力來加快web應用的響應速度
    2. Redis應用場景更豐富,Memcache僅適合做爲緩存使用
  3. Redis的工做模式
    1. 單進程(僅有一個進程處理請求)
    2. 阻塞式(處理請求時具備原子性)
    3. Memcache與之相反,多進程非阻塞式
  4. Redis優缺點
    1. 優勢:無需處理併發問題,下降系統複雜度
    2. 缺點:不適合緩存大尺寸對象(100KB 可修改配置)
  5. Redis計數器
    1. 存儲類型:整數型String
    2. 應用場景
      1. 頻率控制
        1. 接口防刷(key爲IP地址,value爲訪問次數,key生成時間可設置爲1s)
        2. 密碼嘗試次數限制(防止密碼被暴力破解)
      2. 數量統計:請求量統計(相似頻率控制)
      3. 數量控制:商品搶購,獎勵額度控制
    3. 涉及命令
      1. exists key //檢查key是否存在
      2. setnx key value //當key不存在時進行set操做
      3. expire key seconds //設置key的生存時間,沒有ttl返回-1,過時返回-2
      4. ttl ksy //查看key的生存時間
  6. Redis數量控制器
    1. 應用場景
      1. 商品搶購,庫存發生超買超賣
      2. 抽獎限量
      3. 搶紅包
      4. ...
    2. 抽獎限額場景v1版本流程圖
    1. 抽獎限額場景v2版本流程圖
  1. 抽獎限額源碼
 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 }
  1. 併發測試
    1. 使用ab進行壓力測試
    2. ab -c 100 -n 200 http://redis.limitation.test?v=2 //併發數100,請求數200
    3. less -N log/v2.log //查看日誌,檢查結果的正確性
相關文章
相關標籤/搜索