您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么用redis做秒殺支撐的demo”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
用redis做秒殺的庫存扣除, 限制每個賬號只能搶購一次, 這個簡單的demo使用了string, hash, list三種基本類型.
用string類型的int值來存儲剩余庫存, 并在搶購成功后減1
用hash來存儲"已搶購到"的會員的id(可以確保用戶id作為field的唯一性). 注意: 這個hash的field對應的uid不一定搶購成功
用list來保存真正搶購成功的會員id的列表, 作為后續處理訂單的隊列
第一次寫的時候, 嘗試過使用string的bitmap來保存該會員是否搶購成功過, 但是這個在高并發時會出問題, 所以后來換成了唯一field的hash
2個文件:
init.php: 初始化庫存, 統計數據, 搶購成功的會員列表等
buy.php: 搶購
ini.php:
$m_redis = new YourRedisClass(); //redis類很多, 可以自己寫, 也可以用predis等 $m_redis->set('rush_stock', 20);//int, 可搶購的商品總數 $m_redis->set('rush_success', 0); //int, 成功的數量 $m_redis->set('rush_fail', 0); //int, 失敗的數量 $m_redis->expire('rush_queue_h', 0); //hash, 已加入搶購隊列的會員的hash記錄表(field是唯一的, 可限制每個uid只有一次), 不一定搶購成功 $m_redis->set('rush_got_uid', ''); //string, 搶購成功的會員uid記錄, 只是為了能簡單的顯示搶到的會員. $m_redis->del('rush_got_uid_l'); //list, 搶購成功的會員uid(方便搶購后的訂單批次處理) echo 'success, '.date('Y-m-d H:i:s');
執行本文件, 初始化數量.
redis-cli 下執行 "mget rush_stock rush_fail rush_success rush_got_uid" 確認初始化數據
判斷的邏輯:
庫存是否為0, 庫存>0則進入搶購隊列
搶購隊列數據(hash)寫入成功, 則準備扣減庫存
庫存扣減成功(余數>=0)則搶購成功, 進入訂單處理隊列(list)
目前是用string int存儲庫存, 也可以用list的item的個數來計數, 但是初始化時沒有string類型來得簡單.
buy.php
//隨機生成會員id $uid = rand(1,200); $m_redis = new YourRedisClass(); //redis類很多, 可以自己寫, 也可以用predis等 $key = 'rush_stock'; $q = $m_redis->get($key); //1. 先判斷庫存數量 //庫存為0, 直接無法進入搶購隊列 if($q < 1){ $m_redis->incr('rush_fail');//記錄失敗的數量 die($uid.':OutOfStock'); } //2. 判斷該會員是否購買過 => 是否進入過隊列 $queued = $m_redis->hSet('rush_queue_h', $uid, $uid);//這里只能判斷是否進入了搶購的隊列. 如果庫存為0則無法進入. 進入了隊列后才能搶購 if(!$queued){ $m_redis->incr('rush_fail');//記錄失敗的數量 die($uid.':queue failed'); } //讓cpu飛一會 $n = rand(20000,100000); for($i=0; $i < $n; $i++){ $a = rand(1,20000); $a = rand(1,30000); $a = rand(1,40000); $a = rand(1,50000); $a = rand(1,60000); $a = rand(1,70000); $a = rand(1,80000); $a = rand(1,90000); } //3. 扣減數量 $q = $m_redis->decr($key, 1);//扣減數量后會返回結果值 echo $q.' left:'; ////region 如果不判斷操作后返回的結果,則可能會造成超發 //$m_redis->incr('q_success');//記錄成功的數量 ==>這個是有bug的, 不可取 //die(':success'); ////endregion if($q < 0){ $m_redis->incr('rush_fail');//記錄失敗的數量 die($uid.':decrease fail'); }else{ //記錄成功的數量 $m_redis->incr('rush_success'); //記錄該會員已購買 $m_redis->append('rush_got_uid', $uid.','); //字符串追加 $m_redis->rPush('rush_got_uid_l', $uid); //list die($uid.':success'); }
上面的代碼中的hash保存的會員uid, 只是進入搶購隊列的會員uid, 不一定搶購成功了, 那些根本沒有進入搶購隊列的, 也不會在這個hash中, 直接因為庫存為0而被拒絕了.
AB壓力測試: 做一個簡單的500個并發并總計嘗試2000次的請求(測試時, win10下600個并發Nginx就掛機了)
Apache路徑bin>ab -n 2000 -c 500 http://xxx.com/buy.php
redis-cli下執行 "mget rush_stock rush_fail rush_success rush_got_uid" 確認結果, 通過 rush_stock 的值查看可能的超發的數量
執行 "hvals rush_queue_h"可查看進入搶購隊列的用戶id, 這個數量 >= 搶購成功的用戶數量
對于list隊列的數據操作, 可以使用 BLPOP
命令, 這樣可以實現FIFO的數據處理順序.
“怎么用redis做秒殺支撐的demo”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。