常常在面试中被问到如何设计一个高并发环境下的抢购方案,虽然网上的资料已经不少了,可是都是很简单的说了一些用队列之类的套话,没有更详细的细节考虑.被问的实在是太多了,不得已我也仔细想一想这些该怎么设计.抛开运维阶段的多层负载均衡,直接只说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里面