常常在面試中被問到如何設計一個高併發環境下的搶購方案,雖然網上的資料已經不少了,可是都是很簡單的說了一些用隊列之類的套話,沒有更詳細的細節考慮.被問的實在是太多了,不得已我也仔細想一想這些該怎麼設計.拋開運維階段的多層負載均衡,直接只說PHP的業務層面的邏輯.php
整個流程以下:
web界面
點擊搶購==>彈出答題彈窗==>答對斷定當前隊列長度==>隊列未滿就進入隊列,顯示排隊中(狀態),使用wbsocker實時關注用戶狀態
==>答錯再答基本就沒戲了返回失敗
==>隊列滿了,返回失敗web
後端進程
從隊列隨機取部分用戶==>修改他的狀態爲待支付狀態===>用戶點擊支付進行斷定庫存量===>支付完成減庫存面試
在整個過程當中,用戶點擊支付的時候也要斷定庫存,若是沒庫存就顯示失敗;用戶點擊完支付,庫存充足,若是隔了很長時間才輸入密碼支付,這個過程當中若是庫存沒了,要給用戶退款;redis
也就是要麼冗餘部分商品,要麼給用戶退款兩種方案後端
商品的詳細信息
$redis->hGet('product', 'num','name');
商品數量設置的是10,其他字段留着存其餘信息併發
用戶的狀態
1:答題狀態
2:排隊狀態
3:支付狀態
4:搶購成功!
5:搶購失敗 負載均衡
搶購接口:panic_buy.php
1.斷定當前用戶哈希是否存在,若是不存在就設置一下
$redis->hSetNx('taoshihan', 'status', 1);
2.查看當前商品的庫存,若是爲0直接返回失敗,更改用戶狀態爲:5
$redis->hGet('product', 'num');
3.查看如下隊列長度,若是超過1000,直接更改用戶狀態爲:5
$redis->lLen('panic_buying');
3.用戶進入隊列排隊,更改用戶狀態爲:2
$redis->rPush('panic_buying', 'taoshihan');運維
查詢狀態:status.php
對於進入隊列成功的用戶纔會調用到這個接口
1.斷定當前用戶狀態
$redis->hGet('taoshihan', 'status');函數
支付接口:pay.php
1.斷定當前用戶狀態
$redis->hGet('taoshihan', 'status');
2.斷定當前商品數量,若是已經小於10個更改用戶狀態爲:5
$redis->hGet('product', 'num');
3.支付完成修改當前商品數量
$redis->hIncrBy('product', 'num',-1);高併發
後端進程:
獲取下商品數量,若是等於0,就把全部除去進入支付集合的隊列成員更改用戶狀態爲:5
$redis->hGet('product', 'num');
$redis->sIsMember('pay', 'taoshihan');//是否存在於集合中
獲取前100個用戶,更改狀態爲:3,把該用戶同時進入另外一支付集合
$redis->lRange('panic_buying', 0, 99);//獲取前100個
$redis->sAdd('pay' , 'taoshihan');//插入支付集合
PHP-Redis擴展的哈希結構函數
hDel-刪除一個或多個哈希字段
hExists-肯定哈希字段是否存在
hGet-獲取哈希字段的值
hGetAll-獲取哈希中的全部字段和值
hIncrBy-將哈希字段的整數值增長給定數字
hIncrByFloat-將哈希字段的浮點值增長給定數量
hKeys-獲取哈希中的全部字段
hLen-獲取哈希中的字段數
hMGet-獲取全部給定哈希字段的值
hMSet-將多個哈希字段設置爲多個值
hSet-設置哈希字段的字符串值
hSetNx-設置哈希字段的值,僅當該字段不存在時
hVals-獲取哈希中的全部值
hScan-掃描成員的哈希鍵
hStrLen-獲取與哈希中的字段關聯的值的字符串長度
PHP REDIS擴展的列表的函數
blPop,brPop-刪除並獲取列表中的第一個/最後一個元素
bRPopLPush-從列表中彈出一個值,將其推到另外一個列表中並返回
lIndex,lGet-經過列表從其索引中獲取元素
lInsert-在列表中的另外一個元素以前或以後插入一個元素
lLen,lSize-獲取列表的長度/大小
lPop-刪除並獲取列表中的第一個元素
lPush-在列表前添加一個或多個值
lPushx-僅在列表存在時纔在列表前添加值
lRange,lGetRange-從列表中獲取一系列元素
lRem,lRemove-從列表中刪除元素
lSet-經過其索引設置列表中元素的值
lTrim,listTrim-將列表修剪到指定範圍
rPop-刪除並獲取列表中的最後一個元素
rPopLPush-刪除列表中的最後一個元素,將其附加到另外一個列表中並返回(redis> = 1.1)
rPush-將一個或多個值添加到列表
rPushX-僅在列表存在時將值附加到列表
PHP-Redis擴展集合的操做方法
sADD 添加一個或多個成員到集合裏面sCard, sSize 獲取一下集合中成員的個數sDiff 在N個集合中比較出差集sDiffStore 和sDiff差很少,可是把差集結果存儲在第一個key裏面sInter 返回多個集合的交集sInterStore 和sInter相似,把結果存儲在第一個key裏面sIsMember, sContains檢查參數中的成員是不是集合中的一員sMembers, sGetMembers 得到集合中的全部成員sMove 把集合中的成員從一個集合移動到另外一個集合sPop 在集合中隨機刪除一個並獲取到這個成員sRandMember 在集合中隨機獲取一個成員,並不刪除它sRem, sRemove 在集合中刪除指定成員sUnion 返回多個集合的並集sUnionStore 把多個集合的並集存儲在第一個參數key裏面