PHP+Redis实现高并发下商品超卖问题
对于一些有一定用户量的电商网站,如果只是单纯的使用关系型数据库(如MySQL、Oracle)来做抢购,对数据库的压力是非常大的,而且如果不使用好数据库的锁机制,还会导致商品、优惠券超卖的问题。我所在的公司也遇到了同样的问题,问题发生在优惠券被超量抢购上,在问题发生后我们开始想办法解决问题,由于自己使用redis比较多,我准备使用redis来解决这个问题。利用redis的高性能和事务特性来解决线上优惠券被超库存抢购的问题,下面我给出我临时解决这个问题的第一版的伪代码,去掉了一些细节:
/**
* 抢优惠券(秒杀)
* @param int $couponId 商品ID
* @param int $uid 用户ID
* @return bool
*/
function secKill($couponId, $uid)
{
//1.初始化Redis连接
$redis = new Redis();
if (!$redis->connect('127.0.0.1', 6379)) {
trigger_error('Redis连接出错!!!', E_USER_ERROR);
} else {
echo '连接正常<br>';
}
//秒杀商品的库存key
$key = 'secKill:'.$couponId.':stock';
$redis->watch($key);
//获取库存
$stock = $redis->get($key);
//秒杀未开始,表示库存为null
if (!$stock && !is_numeric($stock)) {
echo '秒杀未开始';
return false;
}
//判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束
if ($stock <= 0) {
echo '秒杀已结束';
return false;
}
//用户已经成功秒杀过一次了,不允许再次参与秒杀
if ($redis->sIsMember('secKill:'.$couponId.':uid', $uid)) {
echo '秒杀失败';
return false;
}
//代码走到这里,说明该用户是第一次参与秒杀,将库存减一,然后把这个人放到已抢到的集合表
$redisMulti = $redis->multi();
$redisMulti->decr($key);
$redisMulti->sAdd('secKill:'.$couponId.':uid', $uid);
$result = $redisMulti->exec();
if (empty($result)) {//事务被取消
echo '秒杀失败';
return false;
}
//抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券
$redis->lPush('couponOrder', $couponId.'+'.$uid);
return true;
}
$couponId = 11211;
$uid = mt_rand(1, 100);
secKill($couponId, $uid);
首先,我模拟设置优惠券ID为11211的优惠券库存为10个。

然后,我们使用ab工具来模拟1000次请求,50并发量来测试
ab -n 1000 -c 50 www.test.com/
然后我们通过Redis Desktop Manager来查看一些Redis的结果
couponOrder队列里已经有了10个用户的信息了

并且优惠券的剩余数量也是0了,不再是负数了

同时,用户抢券集合里也保存了10个用户的UID信息。

上面这串代码解决了两个问题:
- 解决了瞬时的大量查询到数据库上给数据库造成很大压力的问题,流量都被拦截在了redis缓存层
- 解决了优惠券被超库存抢购的问题
但是,这段代码也存在一定的问题:
没有使用redis连接池,频繁创建新的redis有一定的性能影响
由于使用了事务,每一次并发请求中只会有一个用户抢券成功,该并发请求中的其它用户都会失败,只能等第二次并发
同样还是事务导致的库存遗留问题,如果有10个商品,1000次请求每次200并发量,5次并发请求就完成了1000次请求,但是只会有5个用户成功抢到,如果没有后续的请求,会导致库存还有5份存量
提示:在消费队列里,如果优惠券发放失败,一定要立即记录并短信通知运营管理人员,看看是否能重发或者通过后台手动定向推送给用户。
所以,后续我又使用了lua脚本和redis配合一起来解决了这个问题。具体代码,我会后续整理处理补充完整。
转载请注明连接:https://www.cnblogs.com/itbsl/p/13418176.html
PHP+Redis实现高并发下商品超卖问题的更多相关文章
- PHP+Redis链表解决高并发下商品超卖问题
目录 实现原理 实现步骤 上一篇文章聊了一下使用Redis事务来解决高并发商品超卖问题,今天我们来聊一下使用Redis链表来解决高并发商品超卖问题. 实现原理 使用redis链表来做,因为pop操作是 ...
- php结合Redis实现高并发下的秒杀抢购功能
实现思路 准备两个队列A和B,假设A队列的名称为stock,用于存放商品总库存信息,B队列的名称为users,用于存放抢购成功后的用户信息.每当有用户进行抢购操作时,先从A队列弹出一个元素,如果该元素 ...
- 使用redis防止抢购商品超卖
前言: redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用. 本篇博文用来测试下使用redis来防止抢购商品超卖问题. 内容: 使用redis的list进行测试 思路是设置一个 ...
- 以商品超卖为例讲解Redis分布式锁
本案例主要讲解Redis实现分布式锁的两种实现方式:Jedis实现.Redisson实现.网上关于这方面讲解太多了,Van自认为文笔没他们好,还是用示例代码说明. 一.jedis 实现 该方案只考虑R ...
- redis防止抢购商品超卖
前言: redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用. 本篇博文用来测试下使用redis来防止抢购商品超卖问题. 内容: 使用redis的list进行测试 思路是设置一个 ...
- php结合redis实现高并发下的抢购、秒杀功能
抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...
- (高级篇)php结合redis实现高并发下的抢购、秒杀功能
抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...
- redis实现高并发下的抢购/秒杀功能
之前写过一篇文章,高并发的解决思路(点此进入查看),今天再次抽空整理下实际场景中的具体代码逻辑实现吧:抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢 ...
- 【转】php结合redis实现高并发下的抢购、秒杀功能
抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存 ...
随机推荐
- rabbitmq部署及配置与验证
1. 场景描述 朋友项目需要弄个测试环境,稍微帮忙了下,系统不复杂,但是需要自己安装mysql.Reids.Es.RabbitMq等,Mq主要用在同步用户信息与发送站内消息和短信上,RabbitMq以 ...
- 【Linux】Linux常用命令及操作 (一)
一.Linux简介 二.Linux基础命令 三.工作常用命令 --------------------------------------------------------------------- ...
- Integer和Long部分源码分析
Integer和Long的java中使用特别广泛,本人主要一下Integer.toString(int i)和Long.toString(long i)方法,其他方法都比较容易理解. Integer. ...
- Spring Boot 2.3.0正式发布:优雅停机、配置文件位置通配符新特性一览
当大潮退去,才知道谁在裸泳..关注公众号[BAT的乌托邦]开启专栏式学习,拒绝浅尝辄止.本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈.MyBatis. ...
- bootstrap中模态框如果放入form表单中会存在的问题
bootstrap中模态框如果放入form表单中会存在的问题:当模态框显示时,点回车会出现表单自动提交!!!所以在使用模态框的时候要特别注意!
- TCP 和 UDP,哪个更胜一筹
作为 TCP/IP 中两个最具有代表性的传输层协议,TCP 和 UDP 经常被拿出来相互比较.这些协议具体有什么区别,又是什么作用呢? 在 IT 圈混迹多年的小伙伴们,对 TCP 和 UDP 肯定再熟 ...
- 为什么大家都在用Fiddler?
在我们做接口测试的时候,经常需要验证发送的消息是否正确,或者在出现问题的时候,查看手机客户端发送给server端的包内容是否正确,就需要用到抓包工具.常用的抓包工具有fiddler.wireshark ...
- Ethical Hacking - Web Penetration Testing(10)
SQL INJECTION SQLMAP Tool designed to exploit SQL injections. Works with many DB types, MySQL, MSSQL ...
- scratch编程我的世界3D史蒂夫
这个程序我们只能制作出一个3D模型而已,并不是真正的我的世界整个游戏: 效果很炫酷吧!现在我们就来看看是怎样编程的吧! 首先,这个模型是有无数个平面克隆体摞在一起,旋转后会产生一种立体的错觉,是不是有 ...
- JavaScript数组在指定某个元素前或后添加元素
//原数组 var s = [['g','g'],['h','h'],['i','i']]; //要添加的元素 var s1 = ['a','b','c']; //要添加的元素 var s2 = [' ...