秒殺這個問題,一直以來都是經典的面試題。但是秒殺也分大小。如果一個產品的用戶不超過5w,上來就問雙十一級別的秒殺。那就沒有意思了~,所以今天就簡單聊下一般條件下的秒殺的思路。方法只有兩個,一個是裝載秒殺商品。一個就是模擬用戶進場秒殺。

工具介紹
首先環境就比較簡單
- Apache
- PHP 7.3
- redis
框架我選擇的ThinkPHP5.1 不過這次我主要還是選擇貼近原生的寫法
選擇apache的原因很簡單。自帶壓力測試工具ab。符合我們的需要。雖然我們知道nginx來做web服務器性能更好。
php7.* 這個不用多介紹了PHP 7 和 PHP 5的性能不是一個世界的
redis 雖然可以實現秒殺的方式有很多。redis算是非常常見的緩存和中間件工具了。在性能和上手難度上都是很不錯的選擇
一.裝載秒殺商品
我們先假設我們有300個人來搶30件商品。那么我們就在我們的商品庫里面裝載30件不同id的商品
秒殺商品一般都是定時添加的。所以我們需要一個定時任務控制器用cli模式執行
class Crontab { public function addGoods() { //設定商品數量 $count=30; $listKey="2019_04_15_goods_list"; //創建連接redis對象 $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); for ($i=1;$i<=$count;$i++){ //將商品id push到列表中 $redis->rPush($listKey,$i); } } }
然后當我們需要裝載商品的時候我們使用php命令去執行下我們的方法
php /項目地址/public/index.php index/crontab/addgoods
用redis客戶端查看下商品id是否放入成功

二.秒殺商品
秒殺商品其實就是一個將集合中的商品id取出和用戶id綁定的過程。只是這個過程進行的非常的快。那么我們將秒殺分為兩步,如果秒殺成功,則記錄下用戶id和商品id 也就是所謂的秒殺訂單。如果秒殺失敗,我們則簡單的記錄一個秒殺失敗的人數。來確定這次秒殺有多少有效用戶參與。
public function kill() { //假裝是用戶的唯一標識 $uuid=md5(uniqid('user').time()); //創建連接redis對象 $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); $listKey="2019_04_15_goods_list"; $orderKey="2019_04_15_buy_order"; $failUserNum="2019_04_15_fail_user_num"; if ($goodsId=$redis->lPop($listKey)) { //秒殺成功 //將幸運用戶存在集合中 $redis->hSet($orderKey,$goodsId,$uuid); }else{ //秒殺失敗 //將失敗用戶計數 $redis->incr($failUserNum); } echo "SUCCESS"; }
壓力測試模擬秒殺
剛剛有提到會使用apache自帶的ab做測試
小試牛刀 300並發 3000訪問量
ab -c 300 -n 3000 http://shop.example.com/index.php/index/index/kill
啥也不說就是干

雖說還是比較慢,但是3000次請求,是全部命中沒有死掉的用戶。加上我本身docker性能沒給到最大。加上只有單機節點。我對這個成績還是比較滿意的
下面來看看搶到商品的幸運用戶
[root@2f7621a62356 bin]# redis-cli
127.0.0.1:6379> HGETALL 2019_04_15_buy_order

再看看秒殺失敗的用戶數量

這時候的商品list已經空空如也了。
好了,今天簡單做個秒殺,就介紹到這里。有時候思路比實現的方法更重要。
鏈接:https://www.jianshu.com/p/aa18f15e1bf0