## 秒殺場景的簡單實現
完整的版的在遷移博客的時候搞丟了。。。。
隊列的特性在日常開發中還可以用于流量削鋒跟解耦。這里做流量削鋒的秒殺搶購場景的簡單示例。
~~~
//監聽已搶購的數量
Redis::watch("sk:1:num"); //已經秒殺完的商品數量
$skNum = Redis::hget("sk:h:1",'gum'); //秒殺商品Hash信息
$isSkNum = (int)Redis::get("sk:1:num");
if($isSkNum < $skNum ){
$uid = $this->rand(5);//隨機生成用戶id
// 暫時用setnx 跟 expire 處理限購 問題是并發情況下會不止10個人進來,但是不影響限購啊
// 沒有考慮到更好的解決方案,先這么處理吧
// Redis::set("sk:su:1", 1 , 'NX', 'EX', "1000"); 不清楚predis下set 同時設置 NX和EX為什么老是不生效,暫時用下邊的方法處理
if(Redis::setnx("sk:su:".$uid,$uid)){
Redis::expire("sk:su:".$uid,10); //設置過期時間,保證10秒內一個用戶只能秒殺成功一次
}else{
Rddis::incr('fail');
echo "10秒內允許搶購一次。";
}
//上述代碼不能放在multi之內。 否則if(Redis::setnx("sk:su:".$uid,$uid)) 會報錯
//放在multi當中,相當于未執行,結果不會返回,所以會一直報錯
Redis::multi();
Redis::incr('sk:1:num');
Redis::lpush("sk:l:1",$uid);
Redis::exec();
}else{
Redis::incr('fail');
echo "不好意思,秒殺已經結束了。";
}
~~~
* * *
ab 1000請求 100并發的請求結果:
~~~
127.0.0.1:6379> get sk:1:num
"10"
127.0.0.1:6379> lrange sk:l:1 0 -1
1) "t106A0502910239"
2) "160A50HR21k23R9"
3) "160i7O502f12Y39"
4) "160j5021W23UzZ9"
5) "Wd160c5i0212539"
6) "1Pw60I502Ae1239"
7) "146050RgG213239"
8) "1605p0aL212p3u9"
9) "16050wyAa2123Y9"
10) "16050fi2012f3j9"
~~~