redis秒杀(PHP版本)
前提提要
今天产品端提了个需求,院校组要求借调我去帮忙,因为我以前做过商城,现在他们需求做一个积分商城,需要做一个秒杀模块,结果毫无意外的我被借调过去了,刚好可以复习一下以前的知识,现在介绍一下redis的秒杀机制,首先大家需要了解redis的基础信息,可以参考小编的前面的文章 https://blog.csdn.net/masterphp/article/details/130728703,现在开始介绍redis秒杀,只要有两种方式来实现,锁和队列
秒杀流程概述
在进行Redis的实现之前,我们先简要介绍一下秒杀的流程:
1.用户在前端页面选择要秒杀的商品,并提交订单;
2.系统校验用户提交的订单是否合法,如商品库存是否充足、用户是否符合参加条件等;
3.系统将订单信息写入数据库,并返回给用户订单处理中的状态;
4.用户在订单处理中不断轮询订单状态,直到订单完成。
在秒杀流程中,系统需要进行多次校验和处理,其中最关键的部分就是判断商品库存是否充足,这部分需要保证数据的可靠性和并发性。
秒杀实现原理
1.使用Redis队列存储订单:秒杀活动中,会有大量的订单请求同时涌入系统,若采用传统的关系型数据库进行存储,会导致并发量过大,数据库连接数量过多,从而降低系统的性能和稳定性。为了解决这个问题,我们可以使用队列来存储订单信息。Redis中提供了List类型的数据结构,可用作队列的实现。通过将订单信息放入Redis队列中,系统可以快速处理大量的订单请求,并以先到先服务的顺序进行处理。
2.使用Redis预减库存:秒杀活动中,需要对商品库存进行实时监控,否则会因为库存不够而导致订单处理失败。但是,如果每个订单都从数据库中查询商品库存,将会增加数据库的压力,导致系统并发性能降低。
为了解决这个问题,我们可以使用Redis的预减库存策略。当用户抢购时,我们先使用Redis缓存中的商品库存信息,并实时更新该缓存信息,如果库存已经减少至0,则直接返回秒杀失败。
3.使用Redis分布式锁:在秒杀活动中,虽然我们使用Redis队列和预减库存,但是系统仍然需要面对大量的并发请求。在这些请求中,可能会有多个用户同时对同一个商品进行抢购,这就需要我们使用分布式锁来保证数据的可靠性。Redis的分布式锁使用方式非常简单,在抢购开始时,我们使用Redis的SETNX操作来尝试获取分布式锁,如果获取成功,则对库存进行操作,操作完成后,释放分布式锁。如果获取分布式锁失败,则需等待一段时间重试。
乐观锁实现方式
//添加商品库存
public function addGoodsStock(Request $request)
{
//接受数据
$goods_id = $request->input('goods_id');
$store = $request->input('store');
//设置商品库存的key
$key = 'seckill_goods_id_'.$goods_id;
$res = Redis::set($key,$store);
return $res;
}
//用户秒杀商品
public function buy(Request $request)
{
//接受数据
$uid = $request->input('uid');
$goods_id = $request->input('goods_id');
//商品库存key
$key = 'seckill_goods_id_'.$goods_id;
//监听对应的key,事务提交之前,如果key被修改,则事务被打断
Redis::watch($key);
//获取商品库存
$store = Redis::get($key);
//抢购成功用户集合key
$setKey = 'userGoodsSuccess';
//判断该用户是否已经抢购过(该用户id是否在抢购用户集合中)
$userBuyStatus = Redis::sismember($setKey,$uid);
if($userBuyStatus){
return '您已抢过!';
}
if($store){
//记录用户信息,更新库存(保证这一组命令,要么全部成功,要么都不成功)
Redis::multi();//开始事务
Redis::decr($key);//减少库存
//将用户id添加到抢购成功用户集合中
Redis::sadd($setKey,$uid);
$result = Redis::exec();//提交,判断当前的key是否被某个客户端修改了
//结果判断
if($result){
//操作数据库,修改商品库存销量
DB::table('goods')->where('id', $goods_id)->decrement('stock', 1, ['sale' => DB::raw('`sale`+1')]);
//创建订单信息
return '抢购成功!';
}else{
return '抢购失败,请重试!';
}
}else{
return '已抢光!';
}
}
队列实现方式
//初始化库存队列
public function init(Request $request)
{
//接受参数
$goods_id = $request->input('goods_id');
$store = $request->input('store');
//获取key
$key = 'list_seckill_goods_id_'.$goods_id;
//防止对已经设置过的商品库存进行覆盖
if(!empty(Redis::llen($key))) {
return '已经设置了库存';
}
//初始化缓存,删除抢购用户id队列key和成功信息保存key,这个是抢购时生成的,防止错乱,初始化删除
$userListKey = 'user_goods_id_'.$goods_id;
Redis::command('del', [$userListKey, 'success']);
// 将商品存入Redis链表中
for($i = 1; $i <= $store; $i++) {
Redis::lpush($key, $i);
}
//设置过期时间
Redis::expire($key, 120);
echo '商品存入队列成功,数量:'.Redis::llen($key);
}
//redis队列抢购
public function start(Request $request)
{
// 模拟随机登录用户
$uid = mt_rand(1, 9999);
//$uid = $request->input('uid');
$goods_id = $request->input('goods_id');
//获取key
$key = 'list_seckill_goods_id_'.$goods_id;
//从链表的头部删除一个元素,返回删除的元素,因为pop操作是原子性,即使很多用户同时到达,也是依次执行
$count = Redis::lpop($key);
if (!$count) {
return '已抢光!';
}
//已抢购用户id队列
$userListKey = 'user_goods_id_'.$goods_id;
//判断该用户是否已经抢购过(该用户id是否在抢购用户集合中)
$userBuyStatus = Redis::sismember($userListKey,$uid);
if($userBuyStatus){
return '您已抢过!';
}
//将用户id添加到抢购成功用户集合中
Redis::sadd($userListKey,$uid);
$msg = '抢到的人为:'.$uid.',抢到商品的顺序为第'.$count.'个';
Redis::lpush('success', $msg);
//操作数据库,修改商品库存销量
DB::table('goods')->where('id', $goods_id)->decrement('stock', 1, ['sale' => DB::raw('`sale`+1')]);
//创建订单信息
return '恭喜您抢购成功!';
}
相关文章:
redis秒杀(PHP版本)
前提提要 今天产品端提了个需求,院校组要求借调我去帮忙,因为我以前做过商城,现在他们需求做一个积分商城,需要做一个秒杀模块,结果毫无意外的我被借调过去了,刚好可以复习一下以前的知识,现在介…...
图形用户界面(GUI)在AI去衣技术中的作用与重要性
引言: 随着人工智能技术的不断进步,AI去衣这一概念逐渐进入公众视野。它指的是利用深度学习算法,从图片或视频中自动移除人物的衣物,生成相应的“裸体”图像。尽管这项技术在道德和隐私方面引发了诸多争议,但其背后的技…...
如何阅读:一个已被证实的低投入高回报的学习方法的笔记
系列文章目录 如何有效阅读一本书笔记 如何阅读:一个已被证实的低投入高回报的学习方法 麦肯锡精英高效阅读法笔记 读懂一本书笔记 文章目录 系列文章目录第一章 扫清阅读障碍破解读不快、读不进去的谜题一切为了阅读小学教师让你做,但中学老师阻止你做的…...
pycharm 安装“通义灵码“并测试
过程:“File>setting>Plugins” 提示: 翻译之后: 点击"接受"之后,提示一下图片,点击ok 安装完成: 安装完"通义灵码"之后,需要登陆,登陆后测试 参考…...
React 之 useMemo Hook (九)
useMemo 是 React 的一个Hook,它允许你“记住”一些计算值,只有在依赖项之一发生变化时才会重新计算这些值。这有助于避免不必要的重新计算和渲染,从而提高应用程序的性能。 代码栗子(计算一个斐波那契数列的值)&#…...
短视频矩阵系统源码saas开发--可视化剪辑、矩阵托管、多功能合一开发
短视频矩阵系统源码saas开发(可视化剪辑、矩阵托管、智能私信聚合、线索转化、数据看板、seo关键词、子账号等多个板块开发) 短视频矩阵系统是一种集成了多种功能的系统,旨在帮助用户在短视频平台上进行高效的内容创作、管理和发布。根据您提…...
百度大模型文心一言api 请求错误码 一览表
错误码说明 千帆大模型平台API包含两类,分别为大模型能力API和大模型平台管控API,具体细分如下: 大模型能力API 对话Chat续写Completions向量Embeddings图像Images 大模型平台管控API 模型管理Prompt工程服务管理模型精调数据管理TPM&RP…...
Unity调用智谱API(简单操作 文本实时翻译)
代码展示: using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI;public class ZhiPuAi : MonoBehaviour {// API的端点URLpublic string…...
Android 开机启动扫描SD卡apk流程源码分析
在开机的时候,装在SD卡的apk和装在系统盘的apk扫描过程不一样,系统盘apk在系统启动过程中扫描,而SD卡上的就不是,等系统启动好了才挂载、扫描,下面就说下SD扫描的流程: 在SystemServer启动MountService&am…...
如何恢复回收站中被删除的文件?3个恢复策略,实测有用!
“刚刚一不小心把回收站清空了,大家有什么好用的方法可以帮我恢复回收站中删除的文件吗?快帮帮我吧!” 在使用电脑的过程中,我们有时可能会不小心将重要的文件或文件夹删除到回收站,并且随后可能进一步从回收站中彻底删…...
Unity---版本控制软件
13.3 版本控制——Git-1_哔哩哔哩_bilibili Git用的比较多 Git 常用Linux命令 pwd:显示当前所在路径 ls:显示当前路径下的所有文件 tab键自动补全 cd:切换路径 mkdir:在当前路径下创建一个文件夹 clear:清屏 vim…...
基于大模型的idea提炼:围绕论文和引用提炼idea之ResearchAgent
前言 对本博客比较熟悉的朋友知道,我司论文项目组正在基于大模型做论文的审稿(含CS英文论文审稿、和金融中文论文审稿)、翻译,且除了审稿翻译之外,我们还将继续做润色/修订、idea提炼(包含论文检索),是一个大的系统,包…...
前端深度扩展
1 为什么要有webpack 模块化管理:构建工具支持Common JS、ES6模块等规范;依赖管理:在大型项目中,手动管理文件依赖关系。webpack可以自动分析项目中的依赖关系,将其打包成1个或多个优化过的文件,减少页面加…...
雷军-2022.8小米创业思考-6-互联网七字诀之专注:有所为,有所不为;克制贪婪,少就是多;一次解决一个最迫切的需求
第六章 互联网七字诀 专注、极致、口碑、快,这就是我总结的互联网七字诀,也是我对互联网思维的高度概括。 专注 从商业角度看,专注就是要“把鸡蛋尽量放在一个篮子里”。这听起来似乎有些不合理,大家的第一反应可能是“风险会不会…...
【禅道客户案例】北大软件携手禅道,开启产品化之路新征程
在项目制项目模式下,软件公司根据客户的需求进行短期项目开发,具有灵活、高效、受众面广的优点,在业界得到了广泛的应用。但这种模式也面临诸多挑战,软件公司需要不断地开发新项目来维持业务增长,由于没有自己的产品也…...
解释泛型(Generics)在Java中的用途
在Java中,泛型(Generics)是一种在编译时期提供类型检查和约束的机制,它使得类和接口可以被参数化,即你可以定义一个类或接口,并通过参数传入具体的类型。泛型增加了代码的复用性和类型安全性,同…...
给网站网页PHP页面设置密码访问代码
将MkEncrypt.php文件上传至你网站根目录下或者同级目录下。 MkEncrypt.php里面添加代码,再将调用代码添加到你需要加密的页进行调用 MkEncrypt(‘123456’);括号里面123456修改成你需要设置的密码。 密码正确才能进去页面,进入后会存下cookies值&…...
124.反转链表(力扣)
题目描述 代码解决(思路1:双指针) class Solution { public:ListNode* reverseList(ListNode* head) {ListNode*temp;//保存cur下一个节点ListNode*curhead;ListNode*preNULL;while(cur){tempcur->next;// 保存一下 cur的下一个节点&#…...
【数据库原理及应用】期末复习汇总高校期末真题试卷06
试卷 一、选择题 1. ________是长期存储在计算机内的有组织,可共享的数据集合. A.数据库管理系统 B.数据库系统 C.数据库 D.文件组织 1. 有12个实体类型,并且它们之间存在15个不同的二元联系,其中4个是1:1联系类型,5…...
Offline:IQL
ICLR 2022 Poster Intro 部分离线强化学习的对价值函数采用的是最小化均方bellman误差。而其中误差源自单步的TD误差。TD误差中对target Q的计算需要选取一个max的动作,这就容易导致采取了OOD的数据。因此,IQL取消max,,通过一个期望回归算子…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
