PHP+Redis链表解决高并发下商品超卖问题
上一篇文章聊了一下使用Redis事务来解决高并发商品超卖问题,今天我们来聊一下使用Redis链表来解决高并发商品超卖问题。
实现原理
使用redis链表来做,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用。
实现步骤
第一步,先将商品库存入队列
/**
* 添加商品数量到商品队列
* @param int $couponId 优惠券ID
*/
function addCoupons($couponId)
{
//1.初始化Redis连接
$redis = new Redis();
if (!$redis->connect('127.0.0.1', 6379)) {
trigger_error('Redis连接出错!!!', E_USER_ERROR);
} else {
echo '连接正常<br>';
}
//根据优惠券ID从数据库中查询该优惠券的库存量
//$sql = "select id, stock from coupon where id = {$couponId}";
$stock = 10; //假设10就是我们从数据库中查询出的该优惠券在数据库中的库存量
//我们现在将这10个库存放入到以该商品ID为key的redis链表中,有几件库存,就存入多少次1,链表长度代表商品库存数
for($i = 0; $i < $stock; $i++) {
$redis->lPush("secKill:".$couponId.":stock", 1);
}
$redis->close();
}
$couponId = 11211;
addCoupons($couponId);
我们调用该方法,然后查看redis,链表中已经添加了10个元素

第二步,抢购开始,设置库存的缓存周期
这一步根据自己的业务来定,如果业务规定,这个优惠券就放出2分钟给用户抢,那么就通过expire()方法给链表设置一个有效期,即使是在有效期内没有抢完仍然有库存也不让用户抢了(由于我们公司业务不对优惠券抢券设置有效期,所以这一步我不需要做)
//设置链表有效期是两分钟
$redis->expire('key', 120);
第三步,客户端执行瞬时抢购操作
/**
* 抢优惠券(秒杀)
* @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>';
}
//将已经成功抢购的用户添加到该以该商品ID为key的集合(set)中
//如果用户已经在集合中,说明用户已经成功秒杀过一次了,不允许再次参与秒杀
if ($redis->sIsMember('secKill:'.$couponId.':uid', $uid)) {
echo '秒杀失败';
return false;
}
//秒杀商品的库存key
$key = 'secKill:'.$couponId.':stock';
//从以该优惠券ID为key的链表中弹出一个值,如果有值,证明优惠券还有库存
$isSockNotEmpty = $redis->lPop($key);
//判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束
if ($isSockNotEmpty != 1) {
echo '秒杀已结束';
return false;
}
//抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券
$redis->lPush('couponOrder', $couponId.'+'.$uid);
//将成功抢券的用户记录到集合中,防止被已抢过的用户再次秒杀
$redis->sAdd('secKill:'.$couponId.':uid', $uid);
$redis->close();
return true;
}
$couponId = 11211;
$uid = mt_rand(1, 100);
secKill($couponId, $uid);
第四步,将成功秒杀的用户入数据库持久化数据,对于并发量不是很大的抢购,我们可以在第三步成功抢购后直接将信息写入数据库,对于并发量比较大的可以放入RabbitMQ消息队列中消费(推荐使用RabbitMQ队列而不是redis是因为RabbitMQ可以保证消息百分之百的被消费,而redis就相对没有那么稳定与可靠)
//此处代码省略
//根据自己的业务场景看看是入数据库还是放入rabbitMQ消息队列中消费
现在我们使用ab工具模拟高并发下的抢券行为(2000次请求数,100并发量)
ab -n 2000 -c 100 www.test.com/
然后我们通过Redis Desktop Manager来查看Redis的结果
同样的,couponOrder队列里已经有了10份包含用户uid和优惠券id的信息了,这些信息可以由队列消费。

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

PHP+Redis链表解决高并发下商品超卖问题的更多相关文章
- PHP+Redis实现高并发下商品超卖问题
对于一些有一定用户量的电商网站,如果只是单纯的使用关系型数据库(如MySQL.Oracle)来做抢购,对数据库的压力是非常大的,而且如果不使用好数据库的锁机制,还会导致商品.优惠券超卖的问题.我所在的 ...
- Redis+Lua解决高并发场景抢购秒杀问题
之前写了一篇PHP+Redis链表解决高并发下商品超卖问题,今天介绍一些如何使用PHP+Redis+Lua解决高并发下商品超卖问题. 为何要使用Lua脚本解决商品超卖的问题呢? Redis在2.6版本 ...
- 使用redis防止抢购商品超卖
前言: redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用. 本篇博文用来测试下使用redis来防止抢购商品超卖问题. 内容: 使用redis的list进行测试 思路是设置一个 ...
- 以商品超卖为例讲解Redis分布式锁
本案例主要讲解Redis实现分布式锁的两种实现方式:Jedis实现.Redisson实现.网上关于这方面讲解太多了,Van自认为文笔没他们好,还是用示例代码说明. 一.jedis 实现 该方案只考虑R ...
- redis防止抢购商品超卖
前言: redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用. 本篇博文用来测试下使用redis来防止抢购商品超卖问题. 内容: 使用redis的list进行测试 思路是设置一个 ...
- PHP和Redis实现在高并发下的抢购及秒杀功能示例详解
抢购.秒杀是平常很常见的场景,面试的时候面试官也经常会问到,比如问你淘宝中的抢购秒杀是怎么实现的等等. 抢购.秒杀实现很简单,但是有些问题需要解决,主要针对两个问题: 一.高并发对数据库产生的压力二. ...
- 利用Redis锁解决高并发问题
这里我们主要利用Redis的setnx的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当前键存在 ...
- 利用 Redis 锁解决高并发问题
这里我们主要利用 Redis 的 setnx 的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当 ...
- 【转】从msql数据库处理高并发商品超卖
今天王总又给我们上了一课,其实mysql处理高并发,防止库存超卖的问题,在去年的时候,王总已经提过:但是很可惜,即使当时大家都听懂了,但是在现实开发中,还是没这方面的意识.今天就我的一些理解,整理一下 ...
随机推荐
- C#远程连接代码
/// <summary> /// 服务连接配置类(验证服务账号是否正确) /// </summary> /// <param name="remoteHost ...
- WPF 最基本的前后台代码对照
最基本的3D代码对照 xaml代码 <Viewport3D> <Viewport3D.Camera> <PerspectiveCamera Position=" ...
- day19 生成器+函数递归
目录 一.yield表达式 1 yield表达式基本用法 二.三元表达式 三.生成式 1 列表生成式 2 字典生成式 3 集合生成式 4 生成器表达式 四.函数的递归 1 递归的定义 2 详解递归 前 ...
- Jmeter(十六) - 从入门到精通 - JMeter前置处理器(详解教程)
1.简介 前置处理器是在发出“取样器请求”之前执行一些操作.如果将前置处理器附加到取样器元件,则它将在该取样器元件运行之前执行.前置处理器最常用于在取样器请求运行前修改其设置,或更新未从响应文本中提取 ...
- linux常用命令(自己感觉常用的)
常用命令 常用指令 ls 显示文件或目录 -l 列出文件详细信息l(list) -a 列出当前目录下所有文件及目录,包括隐藏的a(all) shutdown -r 重启 -h 关机 reboot 重启 ...
- 数据可视化之powerBI技巧(十五)采悟:Power BI动态技巧:动态显示数据层级
今天给大家分享一个动态显示数据层级的技巧,效果如下: 无论想按什么维度.什么顺序查看分析数据,只需要选择不同的切片器组合就行了. 方法如下:01 | 把数据聚合为分析需要的最细粒度 本文假设最细分析粒 ...
- 02 drf源码剖析之快速了解drf
02 drf源码剖析之快速了解drf 目录 02 drf源码剖析之快速了解drf 1. 什么是drf 2. 安装 3. 使用 3. DRF的应用场景 1. 什么是drf drf是一个基于django开 ...
- [USACO3.1]形成的区域(扫描线+离散化)
[USACO3.1]形成的区域(P6432) 日期:2020-05-31 目录 [USACO3.1]形成的区域(P6432) 一.题意分析 二.算法分析 1. 暴力 0). 初始状态(红点为原点) 1 ...
- PowerShell创建参考窗口
背景 平常我们经常遇到这样一个问题,在使用一个窗口工作时常常需要参考其他窗口的文字或图片,此时就需要频繁切换窗口:或者是看视频时需要参考前面进度的画面:或者是阅读或写文档时需要参考其他位置的文字,这时 ...
- 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章
前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...