温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么用redis做秒杀支撑的demo

发布时间:2022-03-25 10:17:53 来源:亿速云 阅读:138 作者:iii 栏目:大数据

本篇内容介绍了“怎么用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" 确认初始化数据

秒杀

判断的逻辑:


    1. 库存是否为0, 库存>0则进入抢购队列


    1. 抢购队列数据(hash)写入成功, 则准备扣减库存


    1. 库存扣减成功(余数>=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”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI