博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Redis实现抢购的一种思路
阅读量:6847 次
发布时间:2019-06-26

本文共 1499 字,大约阅读时间需要 4 分钟。

hot3.png

抢购是如今很常见的一个应用场景,主要需要解决的问题有两个:

1 高并发对数据库产生的压力

2 竞争状态下如何解决库存的正确减少(“超卖”问题)

对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis。重点在于第二个问题,我们看看下面一种常规的实现代码:

'tcp', 'host' => '127.0.0.1', 'port' => '6379'));//redis 登录 $redis->auth('123456');//库存$num = 10;//用户id$user_id = $_SESSION['user_id'];//检查库存 $len = $redis->llen('order:1');if($len >= $num){ exit('已经抢光了');}//把抢到的用户存入到列表中 $result = $redis->lpush('order:1',$user_id);if($result){ echo '抢到了';}?>

如果代码正常运行,列表order:1中最多只能存储10个用户的id,因为库存只有10个。

然而,在使用Apache AB工具模拟很多用户并发请求时,最后发现order:1中总是超过10个用户,也就是出现了“超卖”。

问题就出在这一段代码:

//检查库存 $len = $redis->llen('order:1');if($len >= $num){	exit('已经抢光了');}

在抢购进行到一定程度,假如现在已经有9个人抢购成功,又来了3个用户同时抢购,这时if条件将会被绕过,这三个用户都能抢购成功。而实际上只有一件库存可以抢了。

在高并发下,很多不是问题的,都成了问题。要解决“超卖”问题,核心在于保证检查库存时的操作是依次执行的,形象的说就是把“多线程”转成“单线程”。即使有很多用户同时到达,也是一个个检查并给与抢购资格,一旦库存抢尽,后面的用户就无法继续了。

我们需要使用Redis的原子操作来实现这个“单线程”。首先我们把库存存在goods:1这个列表中,假设有10件库存,就往列表中push10个数,这个数没有实际意义,仅仅代表一件库存。抢购开始后,每到来一个用户,就从goods:1中pop一个数,表示用户抢购成功。当列表为空时,表示已经被抢光了。因为列表的pop操作是原子的,即使有很多用户同时到达,也是依次执行的。抢购的示例代码如下:

'tcp', 'host' => '127.0.0.1', 'port' => '6379'));$redis->auth('123456');//用户ID$user_id = $_SESSION['user_id'];$check = $redis->lpop('goods:1');if(!$check){ exit('抢光了');}$result = $redis->lpush('order:1',$user_id);if($result){ echo '抢购成功';}?>

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

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

转载于:https://my.oschina.net/crazymus/blog/533371

你可能感兴趣的文章
PHP面试常考内容之面向对象(2)
查看>>
CentOS7网卡配置
查看>>
iterator_traits获取迭代器类型
查看>>
小程序页面之间的通讯利器 - nsevent
查看>>
如何编写linux下nand flash驱动-4
查看>>
poj-1146 ID codes
查看>>
2018-08-31
查看>>
jQuery Validate自定义各种验证方法
查看>>
Visual D 0.49.0 发布,支持 Visual Studio 2019
查看>>
国内首台,智能机器人巡逻深圳机场
查看>>
C链表的简单案例
查看>>
机器学习第3周:算法学习
查看>>
Spring装配Bean---使用xml配置
查看>>
mysql基本使用
查看>>
**15.app后端怎么设计用户登录方案(API权限安全)
查看>>
Wiresahrk抓包选项设置
查看>>
二进制的补码、反码
查看>>
Effactive Java -- 对于所有对象都通用的方法
查看>>
Silverlight学习笔记之使用TranslateTransform控制对象位置
查看>>
PyQT实现扩展窗口,更多/隐藏
查看>>