之前写过一篇文章,高并发的解决思路(点此进入查看),今天再次抽空整理下实际场景中的具体代码逻辑实现吧:
抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢?

常规写法:

查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数

这里我就只谈redis的解决方案吧...
我们先来看以下代码(这里我以laravel为例吧)是否能正确解决超抢/卖的问题:

<?php$num = 10;   //系统库存量$user_id =  \Session::get('user_id');//当前抢购用户id$len = \Redis::llen('order:1');  //检查库存,order:1 定义为健名if($len >= $num)return '已经抢光了哦';$result = \Redis::lpush('order:1',$user_id);  //把抢到的用户存入到列表中
if($result)return '恭喜您!抢到了哦';

如果代码正常运行,按照预期理解的是列表order:1中最多只能存储10个用户的id,因为库存只有10个。
然而,但是,在使用jmeter工具模拟多用户并发请求时,最后发现order:1中总是超过5个用户,也就是出现了“超抢/超卖”。
分析问题就出在这一段代码:

 $len = \Redis::llen('order:1');  //检查库存,order:1 定义为健名if($len >= $num)return '已经抢光了哦';

在抢购进行到一定程度,假如现在已经有9个人抢购成功,又来了3个用户同时抢购,这时if条件将会被绕过(条件同时被满足了),这三个用户都能抢购成功。而实际上只剩下一件库存可以抢了。
在高并发下,很多看似不大可能是问题的,都成了实际产生的问题了。要解决“超抢/超卖”的问题,核心在于保证检查库存时的操作是依次执行的,再形象的说就是把“多线程”转成“单线程”。即使有很多用户同时到达,也是一个个检查并给与抢购资格,一旦库存抢尽,后面的用户就无法继续了。
我们需要使用redis的原子操作来实现这个“单线程”。首先我们把库存存在goods_store:1这个列表中,假设有10件库存,就往列表中push10个数,这个数没有实际意义,仅仅只是代表一件库存。抢购开始后,每到来一个用户,就从goods_store:1中pop一个数,表示用户抢购成功。当列表为空时,表示已经被抢光了。因为列表的pop操作是原子的,即使有很多用户同时到达,也是依次执行的。抢购的示例代码如下:
比如这里我先把库存(可用库存,这里我强调下哈,一般都是商品详情页抢购,后来者进来看到的库存可能不再是后台系统配置的10个库存数了)放入redis队列:

 $num=10; //库存$len=\Redis::llen('goods_store:1'); //检查库存,goods_store:1 定义为健名$count = $num-$len; //实际库存-被抢购的库存 = 剩余可用库存for($i=0;$i<$count;$i++)\Redis::lpush('goods_store:1',1);//往goods_store列表中,未抢购之前这里应该是默认滴push10个库存数了//echo \Redis::llen('goods_store:1');//未抢购之前这里就是10了

好吧,抢购时间到了:

 /* 模拟抢购操作,抢购前判断redis队列库存量 */$count=\Redis::lpop('goods_store:1');//lpop是移除并返回列表的第一个元素。
 if(!$count)return '已经抢光了哦';
 /* 下面处理抢购成功流程 */
\DB::table('goods')->decrement('num', 1);//减少num库存字段

用户抢购成功后,上面的我们也可以稍微优化下,比如我们可用将用户ID存入了order:1列表中。接下来我们可以引导这些用户去完成订单的其他步骤,到这里才涉及到与数据库的交互。最终只有很少的人走到这一步吧,也就解决的数据库的压力问题。
我们再改下上面的代码:

$user_id =  \Session::get('user_id');//当前抢购用户id
/* 模拟抢购操作,抢购前判断redis队列库存量 */
$count=\Redis::lpop('goods_store:1');
if(!$count)return '已经抢光了哦';$result = \Redis::lpush('order:1',$user_id);
if($result)return '恭喜您!抢到了哦';

为了检测实际效果,我使用jmeter工具模拟100、200、1000个用户并发进行抢购,经过大量的测试,最终抢购成功的用户始终为10,没有出现“超抢/超卖”。

上面只是简单模拟高并发下的抢购思路,真实场景要比这复杂很多,比如双11活动远远比这更复杂多啦,很多注意的地方如抢购活动页面做成静态的,通过ajax调用接口
再如上面的会导致一个用户抢多个,思路:
需要一个排队队列(比如:queue:1,以user_id为值的列表)和抢购结果队列(比如:order:1,以user_id为值的列表)及库存队列(比如上面的goods_store:1)。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在则已抢购,否则未抢购,接着执行库存减1,写入数据库,将此user_id用户同时也进入结果队列。

redis实现高并发下的抢购/秒杀功能相关推荐

  1. java redis实现抢购_【抢购/秒杀】redis实现高并发下的抢购/秒杀功能

    问题: 抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢? 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否 ...

  2. 简单实现redis实现高并发下的抢购/秒杀功能

    简述 抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢? 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大 ...

  3. PHP redis秒杀返回结果,php结合redis实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到 ...

  4. php结合redis实现高并发下的抢购、秒杀功能

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到 ...

  5. 抢购活动php,php结合redis实现高并发下的抢购、秒杀功能

    使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是)先将商品库存如队列<?php $store= ...

  6. PHP 结合redis实现高并发下抢购、秒杀

    抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到 ...

  7. PHP和Redis实现在高并发下的抢购及秒杀功能示例详解

    抢购.秒杀是平常很常见的场景,面试的时候面试官也经常会问到,比如问你淘宝中的抢购秒杀是怎么实现的等等. 抢购.秒杀实现很简单,但是有些问题需要解决,主要针对两个问题: 一.高并发对数据库产生的压力 二 ...

  8. php post发微博,php结合redis实现高并发下发帖、发微博的方法

    本篇文章主要介绍php结合redis实现高并发下发帖.发微博的方法,感兴趣的朋友参考下,希望对大家有所帮助. 发帖.发微博.点赞.评论等这些操作很频繁的动作如果并发量小,直接入库是最简单的 但是并发量 ...

  9. Redis 的高并发实战:抢购系统 --浅奕

    简介: 主要内容: 一.IO 模型和问题 二.资源竞争与分布式锁 三.Redis 抢购系统实例 主要内容: 一.IO 模型和问题 二.资源竞争与分布式锁 三.Redis 抢购系统实例 一.IO 模型和 ...

  10. go http 并发数限制_618临近,Redis优化高并发下的抢枪抢买买买性能

    随着618的临近,各种促销活动开始变得热门起来,比较主流的有秒杀.抢优惠券.拼团等等.涉及到高并发争抢同一个资源的主要场景有秒杀和抢优惠券. 本文内容 使用Redis优化高并发场景下的接口性能 数据库 ...

最新文章

  1. Spark Shuffle原理解析
  2. AngularJS2 + ASP.NET MVC项目
  3. 史上最极客科技演示今日诞生
  4. 【C 语言】内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )
  5. 计算机视觉算法——图像分类网络总结
  6. 【转】C 从函数返回数组
  7. iOS组件化-带你一步步实现项目的组件化
  8. 安卓设置Activity切换动画无效的问题
  9. bzoj4403-序列统计【Lucas,组合数学】
  10. 【转】Java:String、StringBuffer和StringBuilder的区别
  11. cordova 项目添加splash启动界面
  12. 前端学习(2777):组件之间的通讯方式
  13. 微服务架构 —— 服务雪崩与容错方案
  14. STL 算法接口及用法说明
  15. 实验3: DHCP 基本配置
  16. 【企业架构】什么是 TOGAF? 企业架构方法论
  17. linux加载dl580网卡驱动,HP DL580 G7 服务器在LINUX5 下的集成网卡怎么安装?_电脑_天涯问答_天涯社区...
  18. 同个网络找不到计算机打印机共享,局域网共享打印机搜索不到怎么办 局域网共享打印机搜索不到解决方法...
  19. java 图片识别_java实现图片文字识别的两种方法
  20. 电脑开机太慢?这5个方法瞬间提升你的电脑速度

热门文章

  1. 新海诚没有参与制作的作品_爱情可以是哪些样子——盘点新海诚和宫崎骏作品中的爱情故事...
  2. python中new方法详解及_Python中__new__与__init__方法的区别详解
  3. OpenCV-图像处理(19、Canny边缘检测)
  4. linux python tab补全_Linux设置python自动tab自动补全
  5. kafka应用场景_从未如此简单:10分钟带你逆袭Kafka!
  6. 接口接收数据_基于原语的千兆以太网RGMII接口设计
  7. nyoj810 贪心的嘿嘿(想弄死这出题的)
  8. c语言中用了double语句,求助 C语言 中 double语句用法
  9. 多精度数带余除法_算法笔记 (一) 高精度
  10. PAT 乙级A1025 适合当算法入门练习题做