基於Redis/Memcached的高並發秒殺設計


 如何設計高並發時的秒殺,是面試電商技術職位時必考的題目。今天在這里分享一下基於Redis或Memcached的技術方案,能解決重復提交、超發、高並發的問題。

 <?php 

//預定義總庫存
define("TOTAL_STOCK", 5);
//預定義商品編號
define("ITEM_ID", "ITEM_001");

$userId = $_GET['userId'];
$userIdKey = ITEM_ID . '_' . $userId;

$redis = new redis();
//如果有多台Redis服務器,可根據商品編號哈希后得到其中一台redis的地址
$result = $redis->connect('master104', 6379);

//獲取之前已經領取掉的數量
$requested = $redis->get("requested");
echo "領取前庫存: " . (string)(TOTAL_STOCK - $requested) . "<br />";

//如果已領取大於預定義庫存,則認為庫存為零,不允許繼續
if ($requested && ($requested >= TOTAL_STOCK))
{
  echo "已領完,請下次再來";
  die();
}

//通過設置用戶對該商品的領取狀態,來檢查該用戶是否已領取過
//如果使用Memcached的話,可以使用cas()
if (!$redis->setnx($userIdKey, 1))
{
  echo "您已領取過該商品,不允許重復領取";
  die();
}

//增加領取數量以減少庫存。
//高並發情況下可能會有多個incr()是成功的。但是沒關系,在領取數大於庫存數后,通過下面的if判斷后,后面的請求都是無效的。
$requested = $redis->incr("requested");

//如果嘗試增加的時候,發現庫存已經為零了,需要重置用戶領取狀態
if ($requested && ($requested > TOTAL_STOCK))
{
  $redis->del($userIdKey);
  echo "已領完,請下次再來";
  die();
}

//以下可以做其他的后續操作,比如各種異步並行操作,或是投遞消息到隊列,等等
//Step1
//...
//StepN

//如果步驟進行到這里,不管以上的異步操作進行得如何,我們都必須認為用戶已經領取成功。
//即使有任何失敗,我們都需要用技術手段幫用戶完成上述Step1到StepN
echo "領取成功!<br />";
echo "領取后庫存: " . (string)(TOTAL_STOCK - $requested) . "<br />";


?>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM