1. 程式人生 > >使用redis秒殺出現產品超發現象求解?

使用redis秒殺出現產品超發現象求解?

最近在做一個秒殺活動,處於效能和響應速度的考慮,使用了redis。寫的時候就特別注意了杜絕超發現象,基於redis理論的cas(check and set)樂觀鎖,想著應該能夠杜絕該問題,但是還是出現了,很疑惑求大神幫助,具體的程式碼大致如下:

<?php  
header("content-type:text/html;charset=utf-8");  
$redis = new redis();  
$result = $redis->connect('10.10.10.119', 6379);  
$mywatchkey = $redis->get("mywatchkey"
); $rob_total = 100; //搶購數量 if($mywatchkey<$rob_total){ $redis->watch("mywatchkey"); $redis->multi(); //設定延遲,方便測試效果。 sleep(5); //插入搶購資料 $redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time()); $redis->set("mywatchkey",$mywatchkey+1
); $rob_result = $redis->exec(); if($rob_result){ $mywatchlist = $redis->hGetAll("mywatchlist"); echo "搶購成功!<br/>"; echo "剩餘數量:".($rob_total-$mywatchkey-1)."<br/>"; echo "使用者列表:<pre>"; var_dump($mywatchlist); }else
{ echo "手氣不好,再搶購!";exit; } } ?>

重點:上面是錯誤的。。。。。。。。。。。。。。。。。。。。。。。。。。。

我覺得這個程式碼在高併發的情況,仍然會出現超賣現象。假如:只剩 1個獎品的時候,有三個人同時執行 $redis->watch("mywatchkey") 拿到的資料是 99 ,那麼就出現超賣現象了。

如果在A、B都得到99以後,A先執行完了,B才開始watch呢

由於redis是單執行緒讀取,那麼就用最簡單的佇列實現吧。

  1. 在抽獎前先把獎品數量,寫入redis佇列award:100 // 長度為100的 list ,值只是作為是否中獎

  2. 併發抽獎

$award = $redis->lpop('award:100'); // 由於佇列只有100個值,可以確保只有100個人中獎
if(!$award){
    echo "手氣不好,再搶購!";exit;  
}

// 剩下就是中獎操作的事情了
親測,用ab 壓測併發500 請求4000 無超賣!

<?php
header("content-type:text/html;charset=utf-8");
$redis = new redis();
$result = $redis->connect('127.0.0.1', 7379);
$redis->watch("mywatchlist");
$len = $redis->hlen("mywatchlist");
$rob_total = 100; //搶購數量
if ($len < $rob_total) {

$redis->multi();
$redis->hSet("mywatchlist", "user_id_" . mt_rand(1, 999999), time());
$rob_result = $redis->exec();
file_put_contents("log.txt", $len . PHP_EOL, FILE_APPEND);
if ($rob_result) {
    $mywatchlist = $redis->hGetAll("mywatchlist");
    echo "搶購成功!<br/>";
    echo "剩餘數量:" . ($rob_total - $len - 1) . "<br/>";
    echo "使用者列表:<pre>";
    var_dump($mywatchlist);
} else {
    echo "手氣不好,再搶購!";
    exit;
}
} else {

echo "已賣光!";
exit;
}
?>


Optimistic locking using check-and-set。你似乎呼叫反了,應該是先watch,再get。而且樂觀鎖似乎只控制當你修改的時候是否和你原來獲得的一樣,也就是說在高併發情況下很容易出現一堆錯誤,至於超選不是它控制的。