电商系统秒杀二 秒杀场景下如何进行限流

本章学习内容
1、在秒杀页面,客户点击秒杀后,在前台弹出一个验证码,需要用户输入验证码才能往后端发送请求,这样能够错开秒杀下单的时间。
2、通过验证码,对后台下单请求进行保护,防止刷单,即防止绕开前端,直接往后端发送请求(验证码必须要做到防止刷单的功能)。
在这里插入图片描述

在秒杀页面开始秒杀后,客户点击秒杀按钮,要在前台弹出一个验证码,需要用户输入验证码才能往后端发请求,这样能够错开秒杀下单时间。
在我们的实现中,是要将memberId、producrId和验证码的值一起传入后台,后台返回一个token。然后再根据这个tokne拼接一个后台秒杀地址。这个token会存入到redis中。实际秒杀时,会增加一个判断,检测这个token是不是在redis中存在。如果不存在,就是机器刷单

一 电商项目中秒杀的实现流程

1.1 页面操作流程

在tmll-admin中添加秒杀活动,在秒杀活动中先设置活动的开始日期和结束日期,然后添加商品
在这里插入图片描述
这个秒杀活动信息会保存到mysql中。sms_flash_promotion_product_relation表;
同时,添加商品后会将活动商品保存到ZK中。(路径/ZkLock/load_db/{productId})。然后,当访问到商城前端商品页时, http://localhost:8080/#/product/{productId},会检查Redis中的产品信息缓存。如果Redis中没有产品信息,就会重建Redis缓存。key为product:detail:cache:{ProdId}

在这里插入图片描述
然后进入商城的单品页 http://localhost:8080/#/product/32 , product.vue那个"立即购买"的按钮就会变成"立即秒杀";
点击立即秒杀就会进入秒杀页,secKillDetail.vue;
在这里插入图片描述

1.2 代码实现机制

1、从Redis判断商品是否有秒杀活动

一个商品要么就只能秒杀,要么就只能普通购买,这样是否合理? 这就是为什么要单独独立出一套秒杀服务集群。

2、发送后台请求申请验证码。后台返回验证码图片,并将验证码的计算结果保存到Redis

验证码的请求路径里header里的memeberId是怎么进去的。有什么用?
生成验证码图片的这个请求要怎么防刷?

3、保护后台请求接口
输入验证码后,先验证输入的验证码结果,返回一个Token。这个Token会传入到接下来的商品确认页面,同时会保存到Redis当中,表示当前用户有购买秒杀商品的资格。有效期300秒,300秒内必须完成下单,否则就要重新申请秒杀资格。

在后续的下单过程中,需要传入这个Token才能正常下单。

验证码如果输入错误,是如何判断的?

二 如何加强限流方案的安全性

了解整理流程后,要继续深入思考下我们这个限流方案的安全性

2.1 针对验证码

针对验证码的安全性,可以加上之前的验证码内容

1、我们做了这一套机制后,到底有多安全? 下单请求依然是可以用机器人模拟的。

  • 用户ID是存在Cookie当中的,可以拿到。
  • 图形验证码是随机的,那就总有可能产生容易被机器识别的验证码。

2、怎么加强验证码本身的安全性
这个问题也是必须要前后台配合来思考的,而不是单独靠前端或者后端能够解决的。这个方案要如何设计? 提高验证码安全性的措施:

  • 加干扰线或者干扰点,
  • 将关键字符变形并且在图形上串到一起。
  • 增加更多的前端交互,行为验证。
  • 验证码的内容最好是一个比较复杂的题目,而不是简单的输入数字。这样可以有效延长下单请求的时长,更好的分散请求峰值。
  • 图形验证码可以篡改。可以用PostMan另外访问生成图形验证码的接口,这时Redis里的值就被篡改了,不再是页面上看到的计算结果了。如何处理?1、增加更多的判断因素,例如IP。2、前端签名,后端验证签名。
  • 输入了验证码之后,存在Redis中的验证码要及时删除。同时生成一个Token,代表当前用户有购买权限。这个Token有效期是非常短的。

针对验证机制的安全性,可以增加一些安全机制

换一种验证码
我们动手来换一种复杂一点的验证码,HappyCaptcha 官网地址: https://gitee.com/ramostear/Happy-Captcha

换的方式比较简单,首先在pom.xml中加入HappyCaptcha的依赖

<dependency>
	<groupId>com.ramostear</groupId>
	<artifactId>Happy-Captcha</artifactId>
	<version>1.0.1</version>
</dependency>

然后在OmsPortalOrderController中getVerifyCode方法,将生成验证码的部分修改一下:

try {
            //====== HappyCaptcha验证码 =======
            //这个步骤就会完成生成图片并且往response发送的步骤。
            HappyCaptcha.require(request, response).style(CaptchaStyle.ANIM)
                    .type(CaptchaType.ARITHMETIC_ZH)
                    .build().finish();
            Object captcha = request.getSession().getAttribute("happycaptcha"); //HappyCaptcha生成的验证码是String类型
            int code = Integer.parseInt(captcha.toString());
            log.info("验证码答案:{}", captcha);
            redisOpsUtil.set(RedisKeyPrefixConst.MIAOSHA_VERIFY_CODE_PREFIX
                            + memberId + ":" + productId
                    , code
                    , 300
                    , TimeUnit.SECONDS);
//====== HappyCaptcha验证码结束 =======
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return CommonResult.failed("秒杀失败");
        }

这样,前台的验证码就变成了一闪一闪的动画。并且是中文的加减法,更难破解。
可以看到整个HappyCaptcha的实现机制跟我们自己的实现机制是差不多的,也是使用session来存储答案。

其他还有哪些更难以破解的验证码?

2.2 针对下单请求

我们的实现机制是要求将token拼凑到请求路径上来。这跟把token作为参数传递有什么区别?

如果一个模拟程序需要使用机器来参与秒杀抢单,首先需要根据其他用户的请求来分析获取下单路径。如果是同一个请求路径,只是带的参数不同,那机器完全可以尝试用暴力破解的方式来尝试进行下单。如果碰巧传入了一个Redis中的token值,那他就下单成功了。但是现在把参数隐藏到了请求路径当中,动态的请求路径对于下单的机器来说,就比较难试探出请求的地址,这样就增加了他下单的难度。

三 电商整体的秒杀限流方案

我们天天都在说三高,高并发、高可用、高可扩展,那到底应该如何去落地一个三高的设计方案?

构建大并发、高性能、高可用系统中几种通用的优化思路,可以抽象总结为“4 要 1不要”原则。也就是:数据要尽量少、请求数要尽量少、路径要尽量短、依赖要尽量少,以及不要有单点。当然,这几点是你要努力的方向,具体操作时还是要密切结合实际的场景和具体条件来进行。

针对秒杀这个场景,其实方案设计往往比技术细节更为重要。因为你可以想象,每一个秒杀环节的经典问题,都意味着互联网的秒杀业务出现过大的问题,这都是实打实买来的教训。发现了问题之后才会有针对性的方案设计。那现在,我们整体来回顾下电商的秒杀限流方案。

在这里插入图片描述
错峰1:动静分离的本质是将包含浏览者信息的动态数据和不包含浏览者信息的静态资源区分开。例如在商品单品页,商品信息是不包含浏览者信息的,这部分就可以抽象出静态资源。而用户登录状态、cookie等这些动态数据也尽可能缓存起来,并且使缓存能够离用户更近。

错峰2:秒杀答题的形式可以是多种多样的,目的是防止机器刷单,以及错开用户的下单时长。在秒杀场景下,答题速度靠后的请求自然就没有库存了,也可以减少系统的请求量。

错峰3:缓存的作用主要有两个,一是快速扣减库存,保护数据库流量,并且库存扣减完成后,快速通知Nginx,屏蔽后续请求;二是提前识别热点数据,并且针对热点数据提供优化处理。处理的方案主要是三个,一是优化,二是限制,三是隔离,包括业务隔离、系统隔离、数据隔离。

错峰4:单独提供秒杀服务集群,有利于减少秒杀商品的超大流量对普通商品的性能冲击,不要让1%的商品影响到另外的99%。

后台错峰:这一部分是我们的重点。我们这个图中每一个错峰点虽然在图上就是比较简单的一个点,但是深入进去,每个地方要考虑的细节都还是非常多的,大家可以回顾下之前的内容,体会下如何在后端对秒杀服务做针对性的优化。首先想到的是使用MQ进行削峰。但是实际上,后端需要考虑的三高问题也远不止MQ削峰这一步。每一个环节都需要考虑后端组件是否能够承载得住。例如秒杀服务集群,到底应该部署多大的集群?部署多少台机器呢?显然为了顶住秒杀的大流量,秒杀集群就需要部署得非常大。但是,如果在大部分没有秒杀服务的时间内,这个集群的资源就闲置得非常厉害。所以,虚拟化+云计算进行弹性部署也是非常重要的。在我后边博客里会给大家带来k8s和云部署的实战讲解。

然后:在后端系统中,添加了Redis、MQ这样的一些中间产品。而这些产品集群本身,也存在效率低下、服务崩溃的风险。这样也就给系统整体带来了更多的风险点。那要怎么去屏蔽这些产品给系统带来的风险呢?下一节博客会讲系统降级方面的设计;

TAGS
方案优先 > 技术优先。学习技术的同时,都要增加对软件问题的思考,很多同学技术学得很快,但是缺乏思考。秒杀这种超大并发场景下的限流问题,不是任何一个技术或者任何一个步骤可以限制住的,需要一个完整全面的方案才能保证业务稳定性。所以我们在开发过程中,不能只埋头于技术点,要站在更高的角度,整体来理解解决方案,这样才能更深入的理解自己在做的事情,也才能真正来解决问题。这才是高级程序员与普通程序员真正的区别。

例如针对前端验证问题,还有哪些优化方案?
提前发Token。可以在秒杀前设置一个预约活动。 在活动中提前发放token。例如一个秒杀活动有20W个商品,那就可以预先准备200W个token。用户进行预约时,只发放200W个Token,其他人也能预约成功,但是其实没有获得token,那后面的秒杀,直接通过这个token就可以过滤掉一大部分人。相当于没有token的人都只预约了个寂寞。这也是互联网常用的一个套路。

例如针对超卖问题,在之前的课程中,介绍了如何使用Redis分布式锁防超卖。针对同一个商品ID,使用一把分布式锁,确实可以很快很方便的处理超卖问题。但是如果同时进行秒杀的商品多了呢?像京东、淘宝一场大型的秒杀活动,同时有成千上万个商品要进行秒杀,那就意味着同一时间Redis上锁解锁的操作会要执行成千上万次,这对Redis的性能消耗是相当巨大的,Redis就有可能升级成为新的性能瓶颈。这时该怎么办?

当然具体问题的解决方案从来不止一个,这里我们可以选择一种返璞归真的方案,把秒杀超卖的问题从分布式降级到本地JVM中,来获取极限性能。例如将秒杀服务接入配置中心(Nacos),然后在秒杀服务开始前,由配置中心给每个应用服务实例下发一个库存数量。然后每次下单,每个服务器只管自己的库存数量,与其他应用服务器完全不进行库存同步,在各自的内存里扣减库存,这样就不会有超卖的情况发生。减少了网络消耗,性能也能够进一步提升。

这种方案可不可行呢?当然也会有一些问题需要去处理。有可能某给服务器上的库存很快消耗完了,而其他的服务器上仍有库存。整个服务就会表现为你抢不到商品,但是在你后面抢商品的人却能抢到商品。(你们 在参与秒杀时有没有过这样的经历?)但是这在秒杀这种场景下,完全是可以接受的。另外,如果某一个应用服务器挂了,那给他分配的库存就会丢失。这时候又要怎么办?其实也没必要再去设置什么复杂的逻辑,大不了少卖一点出去。反正都是售罄了,全卖完了,和卖了99%,其实没什么区别。这时只需要统计好订单的数量(可以通过MQ来统计,也可以通过Redis统计),等秒杀活动的30分钟等待支付期过去后,再将没卖出去的库存重新丢回库存池,与没有付款而被取消的订单商品一起返场售卖就可以了。这也是很多互联网公司目前采用的方案。

最后虽然我们是后台开发工程师,但是前端也必须要有所了解。今天我们关注的这个问题,也不能只关注后端,需要前后端一起才能理解他的作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/480033.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

通过JWT完成token登录验证

前言 什么是JWT&#xff1f; 全称是JSON Web token&#xff0c;是用于对应用程序上的用户进行身份验证的标记&#xff0c;使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据 使用JWT的优势 提高了程序的可伸缩性&#xff0c;也极大的提高了应用程序的安全…

2024蓝桥杯每日一题(单调队列)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;单调栈 试题二&#xff1a;滑动窗口 试题三&#xff1a;子矩阵 试题四&#xff1a;最大子序和 试题一&#xff1a;单调栈 【题目描述】 给定一个长度为 N 的整数数列&#xff0c;输出每…

第十四届蓝桥杯JavaB组省赛真题 - 幸运数字

进制转换可以参考如下的十进制&#xff0c;基本一样的&#xff0c;只是把10变成了其他数字&#xff0c; sum就是各个数位之和 public static int myUtil(int n) {int sum 0;while(n > 0) {sum n % 10;n / 10;}return sum;} 注意&#xff1a; 如果写在同一个类里面&…

基于javaSpringboot+mybatis+layui的装修验收管理系统设计和实现

基于javaSpringbootmybatislayui的装修验收管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留…

Java安全 反序列化(5) CC6链原理分析

Java安全 反序列化(5) CC6链原理分析 CC6学习的目的在于其可以无视jdk版本&#xff0c;这条链子更像CC1-LazyMap和URLDNS链子的缝合版 文章目录 Java安全 反序列化(5) CC6链原理分析前言一.CC6的原理和实现以及易错点我们如何实现调用LazyMap.get()方法一个易错点 二.完整CC6P…

亚马逊服务器ssh以及scp

ssh awspass.pem为创建服务器时创建的密钥&#xff0c;ubuntu用户 ssh -i "awspass.pem" ubuntuipscp scp -i "awspass.pem" -r dist/* ubuntuip:/home/ubuntu/

macOS下Java应用的打包和安装程序制作

文章目录 macOS应用程序结构Java应用打包JavaAppLauncherjpackage其它相关JDK命令附录JavaAppLauncher源码链接macOS应用程序结构 macOS通常以dmg或pkg作为软件发行包,安装到/Applications下后,结构比较统一。 info.plist里的CFBundleExecutable字段可以指定入口,如果不指定…

使用uniapp 的 plus.sqlite 操作本地数据库报错:::table xxx has no column named xxxx

背景&#xff1a; 1、使用uniapp 的 plus.sqlite 进行APP本地数据库操作 2、SQLite 模块用于操作本地数据库文件&#xff0c;可实现数据库文件的创建&#xff0c;执行SQL语句等功能。 遇到&#xff1a;在之前创建的表上进行新增字段的操作时候&#xff0c;出现问题&#xff1a…

蓝桥杯 2022 省B 砍竹子

思路&#xff1a; 非常明显&#xff0c;这题是个贪心。因为这题是求最小操作次数&#xff0c;而且每次操作都会变小&#xff0c;所以肯定要优先操作大的元素&#xff0c;这样它变小之后才可能和其它元素一起操作以减少操作次数。 所以&#xff1a;建立两个数组&#xff0c;一…

Canine IP-10/CXCL 10 ELISA试剂盒上新

科研用Canine IP-10/CXCL 10 ELISA试剂盒重磅来袭&#xff0c;将在免疫学、癌症研究与神经科学等多个领域助力各位老师们的研究&#xff01; 图1&#xff1a;犬IP-10/CXCL10结构预测&#xff08;图片来源&#xff1a;UniProt&#xff09; C-X-C基序趋化因子(C-X-C motif chemok…

绿色节能|AIRIOT智慧建材能耗管理解决方案

建材供应是建筑业不可或缺的一个重要环节&#xff0c;在环保和企业可持续发展的双重需求下&#xff0c;建材生产商对建材生产过程中的能耗掌握和能耗管理尤其关注。但在实际生产和运营过程中&#xff0c;传统的建材能耗管理方式往往存在如下痛点&#xff1a; 用户管理权限不完善…

什么是单点登录?

单点登录&#xff08;Single Sign On&#xff0c;简称 SSO&#xff09;简单来说就是用户只需在一处登录&#xff0c;不用在其他多系统环境下重复登录。用户的一次登录就能得到其他所有系统的信任。 为什么需要单点登录 单点登录在大型网站应用频繁&#xff0c;比如阿里旗下有淘…

Unity发布webgl之后打开PDF文件,不使用js,不和浏览器交互

创建一个按钮&#xff0c;然后点击就会打开 在webgl下要使用这样的路径拼接&#xff0c;不然就会报错。 btnBook.onClick.AddListener(() >{var uri new System.Uri(Path.Combine(Application.streamingAssetsPath "/Books", "文档.pdf"));Debug.Log…

短视频矩阵系统---php7.40版本升级自研

短视频矩阵系统---php7.40版本升级自研 1.部署及搭建 相对于其他系统&#xff0c;该系统得开发及部署难度主要在各平台官方应用权限的申请上&#xff0c;据小编了解&#xff0c;目前抖音短视频平台部分权限内侧名额已满&#xff0c;巧妇难为无米之炊&#xff0c;在做相关程序…

Xilink 简单双口ram ip的读写仿真

简单双口RAM有两个端口Port A和port B,其中Port A用于写数据,Port B用于读数据,读写接口可以独立时钟工作。这一点和真双口RAM是有区别的,真双口RAM的A B两个Port都可以进行读写操作。 RAM是FPGA中重要的数据结构,可用于数据的缓存和跨时钟域信号处理。本文就xilin…

Java项目:71 ssm基于ssm+vue的外卖点餐系统+vue

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统功能 系统分为前台订餐和后台管理&#xff1a; 1.前台订餐 用户注册、用户登录、我的购物车、我的订单、商品列表 2.后台管理 商品管理&#xf…

基于OpenCV的图像处理案例之图像矫正(Python)

Index 目录索引 写在前面解决思路参考 写在前面 本文通过一个案例介绍如何使用OpenCV将倾斜的扫描文档图像进行水平矫正。 解决思路 因为扫描图像中的大部分文字倾斜后&#xff0c;同一行文字也在同一条直线&#xff0c;所以可以通过拟合直线来计算文本倾斜角度&#xff0c;…

《剑指 Offer》专项突破版 - 面试题 89 和 90 : 房屋偷盗和环形房屋偷盗(C++ 实现)

目录 面试题 89 : 房屋偷盗 面试题 90 : 环形房屋偷盗 面试题 89 : 房屋偷盗 题目&#xff1a; 输入一个数组表示某条街道上的一排房屋内财产的数目。如果这条街道上相邻的两幢房屋被盗就会自动触发报警系统。请计算小偷在这条街道上最多能偷取到多少财产。例如&#xff0c…

Kafka 3.x(上)

具体课程请看课程简介_哔哩哔哩_bilibili 概念 分布式流处理平台&#xff0c;它以高吞吐量和可扩展性而闻名。相同类型的消息存在于Topic主题中&#xff0c;主题类似于数据库中的表&#xff0c;不过主题存储的数据大多是半结构化的。主题可以包含多个分区&#xff08;分布式的…

STM32之HAL开发——手动移植HAL库

HAL库移植步骤 创建目录 配置启动文件 在\Drivers\CMSIS\Device\ST\stm32f1xx\Source\Templates\ARM目录下&#xff0c;根据你的芯片型号选择对应的启动文件&#xff0c;不同容量大小的芯片&#xff0c;对应的启动文件也不一样。 注意&#xff1a;在HAL库中&#xff0c;不同容…