使用Redis实现抢购的一种思路(list队列实现)
原文:https://my.oschina.net/chinaxy/blog/1829233
抢购是如今很常见的一个应用场景,主要需要解决的问题有两个:
1 高并发对数据库产生的压力
2 竞争状态下如何解决库存的正确减少(“超卖”问题)
对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis。重点在于第二个问题,我们看看下面一种常规的实现代码:
<?php
require('predis/src/Autoloader.php');
$redis = new Predis\Client(array(
'scheme' => '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操作是原子的,即使有很多用户同时到达,也是依次执行的。抢购的示例代码如下:
<?php
//抢购
require('predis/src/Autoloader.php');
$redis = new Predis\Client(array(
'scheme' => '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,没有出现“超卖”。
使用Redis实现抢购的一种思路(list队列实现)的更多相关文章
- [Redis]处理定时任务的2种思路
用redis完成类似 at 命令的功能,例如订单24小时后没有支付自动关闭,定时发邮件,主要说下任务生成之后怎么触发消费. 使用 有序集合 思路: 使用sorted Sets的自动排序, key 为任 ...
- redis缓存击穿问题一种思路分享
思路每一个key都有一个附属key1,附属key1可以是key加特定前缀组成,key对应value为真正的缓存数据,附属key1对应的value不重要,可以是随便一个值,附属key1的作用主要是维护缓 ...
- js数组去重几种思路
在一些后台语言中都内置了一些方法来处理数组或集合中重复的数据.但是js中并没有类似的方法,网上已经有一些方法,但是不够详细.部分代码来源于网络.个人总计如下:大致有4种思路 1)使用两次循环比较原始的 ...
- CSS实现水平垂直同时居中的5种思路
× 目录 [1]水平对齐+行高 [2]水平+垂直对齐 [3]margin+垂直对齐[4]absolute[5]flex 前面的话 水平居中和垂直居中已经单独介绍过,本文将介绍水平垂直同时居中的5种思路 ...
- CSS实现垂直居中的4种思路
× 目录 [1]line-height [2]vertical-align [3]absolute [4]flex 前面的话 相对于水平居中,人们对于垂直居中略显为难,大部分原因是vertical-a ...
- CSS实现水平居中的4种思路
× 目录 [1]text-align [2]margin [3]absolute [4]flex 前面的话 水平居中是经常遇到的问题.看似方法较多,条条大路通罗马.但系统梳理下,其实都围绕着几个思路展 ...
- 应对Memcached缓存失效,导致高并发查询DB的四种思路(l转)
当Memcached缓存失效时,容易出现高并发的查询DB,导致DB压力骤然上升. 这篇blog主要是探讨如何在缓存将要失效时,及时地更新缓存,而不是如何在缓存失效之后,如何防止高并发的DB查询. 解决 ...
- 点击页面div弹窗以外隐藏的两种思路
在本文为大家介绍两种思路实现点击页面其它地方隐藏该div,第一种是对document的click事件绑定事件处理程序.. 第一种思路分两步 第一步:对document的click事件绑定事件处理程序, ...
- 使用 CUDA 进行计算优化的两种思路
前言 本文讨论如何使用 CUDA 对代码进行并行优化,并给出不同并行思路对均值滤波的实现. 并行优化的两种思路 思路1: global 函数 在 global 函数中创建出多个块多个线程对矩阵每个元素 ...
随机推荐
- supervisor管理uwsgi
1. 前言 传统的管理uwsgi服务: 1. 通过shell脚本来编写start restart stop函数来控制 2. 比较麻烦,有时候控制写的烂,还会出现意想不到的错误 supervisor进行 ...
- 算法笔试题整理——升级蓄水池 && 字符串数字表达式计算值 && 求旅游完所有景点需要的最少天数 && 宝箱怪
1. 小米笔试题——升级蓄水池 题目描述: 在米兔生活的二维世界中,建造蓄水池非常简单. 一个蓄水池可以用n个坐标轴上的非负整数表示,代表区间为[0-n]范围内宽度为1的墙壁的高度. 如下图1,黑色部 ...
- MySQL学习笔记:concat、concat_ws、group_concat —— 字符串连接
在MySQL中,实现字符串拼接主要有以下3种函数: concat(x,y,...) concat_ws(分隔符,x,y,...) group_concat(distinct xxx order by ...
- 20165333 预备作业3 Linux安装及学习
预备作业3 Linux安装及学习 Linux系统安装 在老师的教程帮助下成功的完成了虚拟机的安装,但安装过程中也遇到了一些问题.在下载ubuntu时,总是下载失败,在求助同学后,在中文版官网的网址,才 ...
- 将DataTable转换为List,将List转换为DataTable的实现类
将DataTable转换为List,将List转换为DataTable的实现类 public static class DataTableHelper { public static DataTabl ...
- Zookeeper学习笔记-概念介绍
目录 概念 背景介绍 zookeeper一致性 使用建议 概念 ZooKeeper是一个开源的分布式协调服务,它为分布式应用提供了高效且可靠的分布式协调服务,提供的功能包括:配置维护.域名服务.分布式 ...
- Hadoop案例(十)WordCount
WordCount案例 需求1:统计一堆文件中单词出现的个数(WordCount案例) 0)需求:在一堆给定的文本文件中统计输出每一个单词出现的总次数 1)数据准备:Hello.txt hello w ...
- thinkphp和ueditor自定义后台处理方法整合
先了解一下ueditor后台请求参数与返回参数格式规范: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ...
- 深度学习基础系列(九)| Dropout VS Batch Normalization? 是时候放弃Dropout了
Dropout是过去几年非常流行的正则化技术,可有效防止过拟合的发生.但从深度学习的发展趋势看,Batch Normalizaton(简称BN)正在逐步取代Dropout技术,特别是在卷积层.本文将首 ...
- python中的递归问题,求圆周率
以上面一个公式为例: import numpy as np def getPi(n): if n == 0: return np.power(-1,n)*(1.0/(2*n+1)) else: ret ...