經常在面試中被問到如何設計一個高併發環境下的搶購方案,雖然網上的資料已經很多了,但是都是很簡單的說了一些用隊列之類的套話,沒有更詳細的細節考慮.被問的實在是太多了,不得已我也仔細想想這些該怎麼設計.拋開運維階段的多層負載均衡,直接只說PHP的業務層面的邏輯. 整個流程如下:web界面點擊搶購==>彈 ...
經常在面試中被問到如何設計一個高併發環境下的搶購方案,雖然網上的資料已經很多了,但是都是很簡單的說了一些用隊列之類的套話,沒有更詳細的細節考慮.被問的實在是太多了,不得已我也仔細想想這些該怎麼設計.拋開運維階段的多層負載均衡,直接只說PHP的業務層面的邏輯.
整個流程如下:
web界面
點擊搶購==>彈出答題彈窗==>答對判定當前隊列長度==>隊列未滿就進入隊列,顯示排隊中(狀態),使用wbsocker實時關註用戶狀態
==>答錯再答基本就沒戲了返回失敗
==>隊列滿了,返回失敗
後端進程
從隊列隨機取部分用戶==>修改他的狀態為待支付狀態===>用戶點擊支付進行判定庫存量===>支付完成減庫存
在整個過程中,用戶點擊支付的時候也要判定庫存,如果沒庫存就顯示失敗;用戶點擊完支付,庫存充足,如果隔了很長時間才輸入密碼支付,這個過程中如果庫存沒了,要給用戶退款;
也就是要麼冗餘部分商品,要麼給用戶退款兩種方案
商品的詳細信息
$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裡面