Redis 消息隊列構造秒殺原理

搶購、秒殺是現在很常見的一個應用場景,主要須要解決的問題有兩個:
  1 高併發對數據庫產生的壓力
  2 競爭狀態下如何解決庫存的正確減小("超賣"問題)
對於第一個問題,須要查看本站對mysql 具體優化的方案;這裏重點解決後者問題
減小超賣php

操做原理:
使用redis隊列,由於pop操做是原子的,即便有不少用戶同時到達,也是依次執行,推薦使用。mysql

一、在活動開始的前期,秒殺的腳本會將商品的庫存信息緩存到redis中
具體操做 (php)ajax

    <?php
    $store=1000;  // 假設秒殺庫存設置1000個
    $redis=new Redis();  
    $result=$redis->connect('127.0.0.1',6379);  redis

    $res=$redis->llen('goods_stock'); // 查看已經存在的庫存
    var_dump($res);sql

    if(intval($res)>=$store){
       var_dump('庫存加滿了');
       die();
    }數據庫

    $count=$store-$res;  
    for($i=0;$i<$count;$i++){  
        $redis->lpush('goods_stock',1); // 將庫存列表一次加入redis的列表
    }緩存

    $stock = $redis->llen('goods_stock');
    var_dump(' 庫存補充到 1000 ');
    ?>併發

二、模擬搶購操做高併發

<?php優化

$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);

$peple = 1009; // 假設有 1009 個用戶來搶商品

for($i=0;$i<$peple;$i++){
   $rrt = $redis->Lpop('goods_stock'); // Lpop 獲取 key 列表的頭元素並移除頭元素
   if($rrt){
     echo '搶到了 : '.$i.' ; res : '.$rrt; // 搶到了就進行下一步的下單操做
     // TODO 進入正常的訂單流程
   }else {
     echo '售罄了 : '.$i; // 提示用戶沒有搶到
     die();
   }
   echo '<br/>';
}

?>

上述只是簡單模擬高併發下的搶購,真實場景要比這複雜不少,不少注意的地方
如搶購頁面作成靜態的,經過ajax調用接口
再如上面的會致使一個用戶搶多個,思路:

在以上思路的基礎上添加一個 ‘排隊的隊列’,若是搶單的用戶已經在 ‘排隊的隊列’ 的隊列裏了 就提示用戶不能再搶了,並提示搶購失敗。

相關文章
相關標籤/搜索