秒杀系统的设计思路(应对高并发,超卖等问题的解决思路)

首先我们先看一下设计秒杀系统时,我们应该考虑的问题。

解决方案:

 一.页面静态化结合CDN内容分发

前端把能提前放入cdn服务器的东西都放进去,反正把所有能提升效率的步骤都做一下,减少真正秒杀时候服务器的压力。

        秒杀活动的页面内容,大多数都是固定不变的。我们可以对秒杀页面做静态化处理,减少访问服务端的压力。在秒杀活动开始前,提前生成包含秒杀商品信息、倒计时等固定内容的静态 HTML 页面。这些页面可以根据秒杀活动的特点,例如开始时间、结束时间等来预先生成。

示例如下:

// 生成秒杀页面的HTML
public String generateSeckillPage(long goodsId) {GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);// 其他固定信息的获取// 生成HTML页面,包含秒杀商品信息、倒计时等String htmlContent = "<html><head>...</head><body>...</body></html>";// 将HTML页面保存到静态文件,或者存储到数据库中return htmlContent;
}

        参与秒杀的用户可能分布在全国各地,地域不同,网速不同。为了让用户可以快速的进入到秒杀活动的页面,可以使用 CDN(Content Delivery Network,内容分发网络)让用户可以就近获取所需内容。将生成的静态 HTML 页面通过 CDN 分发,使用户可以就近获取所需内容。CDN 的作用是将页面的静态资源分发到全球不同的节点,用户访问时可以从离他们最近的节点获取内容,减少网络延迟,提高访问速度。

        用户访问秒杀活动页面时,直接请求 CDN 上的静态 HTML 页面,不再需要服务端动态生成页面内容。这样可以减轻服务端的压力,提高页面加载速度,提升用户体验。

二.按钮置灰控制

        秒杀活动开始前,按钮一般需要置灰。只有时间到了,才能变得可以点击。 这防止,秒杀用户在时间快到的前几秒,疯狂请求服务器,然后秒杀时间点 还没到,服务器就自己挂了。

三. 服务单一职责

        我们都知道微服务设计思想,也就是各个功能模块拆分,功能那个类似放 一起,再用分布式部署方式进行部署。

        如用户登录相关,就设计个用户服务,订单相关就搞个订单服务等等。那么,秒杀相关业务逻辑也可以放到一起, 搞个秒杀服务,单独给它搞个秒杀数据库。” 服务单一职责有个好处:如果秒杀 没抗住高并发压力,秒杀库崩了,服务挂了,也不会影响到系统其他服。

四.秒杀地址加盐(url动态化)

        链接如果明文暴露的话,会有人获取到请求 Url,提前秒杀了。因此,需要给 秒杀链接加盐。可以让URL 动态化,如通过 MD5 加密算法加密随机字符串来生成,秒杀链接的URL。

时间校验: 通过获取商品的起始时间和结束时间,判断当前时间与秒杀活动的状态(未开始、进行中、已结束),从而判断用户是否可以参与秒杀。

 GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);long startAt = goods.getStartDate().getTime();long endAt = goods.getEndDate().getTime();long now = System.currentTimeMillis();int miaoshaStatus = 0;int remainSeconds = 0;if(now < startAt ) {//秒杀还没开始,倒计时miaoshaStatus = 0;remainSeconds = (int)((startAt - now )/1000);}else  if(now > endAt){//秒杀已经结束miaoshaStatus = 2;remainSeconds = -1;}else {//秒杀进行中miaoshaStatus = 1;remainSeconds = 0;}

        但仅仅是这样的话还是不够的,如果我们的秒杀的真实地址被人知道了,就可以写一个脚本不断的获取北京时间,在秒杀开始的毫秒级别时就可以请求。而且机器能在短时间内发送大量的请求,绝对会对我们的秒杀活动造成巨大的影响。
那怎么办呢?
        我们可以把我们的秒杀地址动态化,也就是通过MD5之类的加密算法去处理我们的秒杀地址,存入 redis缓存中,根据前端请求的url获取path。 判断与缓存中的字符串是否一致,一致就认为请求是正常的。这就是秒杀链接加盐,用这样的方法来阻止恶意用户直接请求我们的秒杀地址。

@RequestMapping(value="/path", method=RequestMethod.GET)
@ResponseBody
public Result<String> getMiaoshaPath( MiaoshaUser user,@RequestParam("goodsId")long goodsId,@RequestParam(value="verifyCode", defaultValue="0")int verifyCode) {if(user == null) {return Result.error(CodeMsg.SESSION_ERROR);}boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);if(!check) {return Result.error(CodeMsg.REQUEST_ILLEGAL);}String path  =miaoshaService.createMiaoshaPath(user, goodsId);return Result.success(path);}public String createMiaoshaPath(MiaoshaUser user, long goodsId) {if(user == null || goodsId <=0) {return null;}String str = MD5Util.md5(UUIDUtil.uuid()+"123456");redisService.set(MiaoshaKey.getMiaoshaPath, ""+user.getId() + "_"+ goodsId, str);return str;}

实现原理总结如下:

  1. 用户通过前端请求获取秒杀地址的path。
  2. 后端根据用户信息、商品ID等生成动态的秒杀地址。
  3. 将生成的地址通过加盐的加密算法处理,存入Redis缓存中,建立用户ID和商品ID的关联。
  4. 用户提交秒杀请求时,携带path参数,后端根据前端请求的URL获取path,再与Redis缓存中的地址进行比对,判断请求的合法性。

通过这种方法,成功防止了用户通过直接请求秒杀地址进行恶意操作,保障了秒杀活动的公正性和安全性。

五.接口限流进行防刷

        一般有两种方式限流:nginx 限流和redis 限流。

为了防止某个用户请求过于频繁,我们可以对同一用户限流;

为了防止黄牛模拟几个用户请求,我们可以对某个 IP 进行限流;

为了防止有人使用代理,每次请求都更换 IP 请求,我们可以对接口进行限流。

1. Nginx 提供了基于令牌桶算法的限流机制,可以有效控制请求的流量。通过配置 ngx_http_limit_req_module 模块,可以设定每个 IP 或每个 URI 的请求频率上限。

http {limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;server {location /api {limit_req zone=one burst=5;# 其他配置}}
}

上述配置中,limit_req_zone 定义了一个名为 one 的限流区域,每个 IP 的请求速率为 1 次/秒,limit_req 用于限制每秒的请求数,burst 指定了可以超出速率的请求数 

2.0为了防止瞬时过大流量压垮系统,还可以使用阿里Sentinel、Hystrix 组件进行限流。

六. 超卖问题解决思路

        只要是一个秒杀系统,就必然会存在超卖问题。不同用户在读请求的时候,发现商品库存足够,然后同时发起请求,进行秒杀操作,减库存,导致库存减为负数。

1.0使用乐观锁解决

        如果要使用乐观锁,那么我们就要给个商品库存一个版本号version字段,在每次我们读取库存的时候把版本号也读取出来,当这一个线程去执行扣减库存的操作的时候,去判断数据库当前的版本号是否是刚刚读取出来的版本号,如果不是则秒杀失败。

/*** 查询商品库存* @param id 商品id* @return*/@Select("SELECT * FROM goods WHERE id = #{id}")Goods getStock(@Param("id") int id);/*** 乐观锁方案扣减库存* @param id 商品id* @param version 版本号* @return*/@Update("UPDATE goods SET stock = stock - 1, version = version + 1 WHERE id = #{id} AND stock > 0 AND version = #{version}")int decreaseStockForVersion(@Param("id") int id, @Param("version") int version);

service层:

/*** 扣减库存* @param gid 商品id* @param uid 用户id* @return SUCCESS 1 FAILURE 0*/@Transactionalpublic int sellGoods(int gid, int uid) {// 获取库存Goods goods = goodsDao.getStock(gid);if (goods.getStock() > 0) {// 乐观锁更新库存int update = goodsDao.decreaseStockForVersion(gid, goods.getVersion());// 更新失败,说明其他线程已经修改过数据,本次扣减库存失败,可以重试一定次数或者返回if (update == 0) {return 0;}// 库存扣减成功,生成订单Order order = new Order();order.setUid(uid);order.setGid(gid);int result = orderDao.insertOrder(order);return result;}// 失败返回return 0;}

2.0使用redis分布式锁

用 Redis  SET EX PX NX + 校验唯一随机值,再删除释放锁。

if (jedis.set(key_resource id, uni request id,"NX","Ex",100s) == 1)[ //加锁try {do something //业务处理catch(){}finally {//判断是不是当前线程加的锁,是才释放if (uni_request id.equals(jedis.get(key_resource_ id))) {jedis.del(lockKey);}}
}
七.MQ异步处理

如果瞬间流量特别大,可以使用消息队列削峰,异步处理。用户请求过来的时 候,先放到消息队列,再拿出来消费。

八.限流&降级&熔断

 限流,就是限制请求,防止过大的请求压垮服务器;

降级,就是秒杀服务有问题了,就降级处理,不要影响别的服务;

熔断,服务有问题就熔断,一般熔断降级是一起出现。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Halcon利用颜色信息提取背景相似的字符区域

Halcon利用颜色信息提取背景相似的字符区域 文章目录 Halcon利用颜色信息提取背景相似的字符区域 本文以一个例子说明利用颜色信息进行目标提取。如图所示&#xff0c;图&#xff08;a&#xff09;为输入的原始图像,目标为提取出字符区域。由图&#xff08;a&#xff09;可见&a…

【前端框架】 了不起的 TypeScript 入门教程

前言 想学习 TypeScript 的小伙伴看过来&#xff0c;本文将带你一步步学习 TypeScript 入门相关的十四个知识点&#xff0c;详细的内容大纲请看下图&#xff1a; TypeScript 是什么 TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集&#xff…

【网络安全常用术语解读】SCAP详解

本文主要介绍什么是SCAP&#xff0c;SCAP的产生背景是怎样的&#xff0c;SCAP有什么用途&#xff0c;有哪些组件&#xff0c;各个组件的用途是什么&#xff1f; SCAP产生背景 由于计算机和网络技术的快速发展&#xff0c;越来越多的软件和系统被应用到企业和机构中&#xff0c…

2023十大编程语言及未来展望

2023十大编程语言及未来展望 1. 2023年十大编程语言排行榜2. 十大编程语言未来展望PythonCCJavaC#JavaScriptPHPVisual BasicSQLAssembly language 1. 2023年十大编程语言排行榜 TIOBE排行榜是根据互联网上有经验的程序员、课程和第三方厂商的数量&#xff0c;并使用搜索引擎&a…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

【数据结构】八、查找

一、基本概念 静态查找&#xff1a;只查找&#xff0c;不改变集合内数据元素 动态查找&#xff1a;有则输出元素&#xff0c;无则添加元素 二、静态查找表 2.1顺序查找 在线性表、链表、树中依次查找 2.2折半查找&#xff08;二分查找&#xff09; 在有序的线性表中&…

前端八股文(工程化篇)

目录 1.常用的git命令有哪些&#xff1f; 2.git rebase和git merge的区别 3.有哪些常见的Loader和Plugin&#xff1f; 4.webpack的构建流程 5.bundle,chunk,module是什么&#xff1f; 6.如何提高webpack的打包速度 7.vite比webpack快在哪里 8.说一下你对Monorepo的理解 …

组合总和[中等]

一、题目 给你一个 无重复元素 的整数数组candidates和一个目标整数target&#xff0c;找出candidates中可以使数字和为目标数target的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates中的 同一个 数字可以 无限制重复被选取 。如果…

再见2023,你好2024(附新年烟花python实现)

亲爱的朋友们&#xff1a; 写点什么呢&#xff0c;我已经停更两个月了。2023年快结束了&#xff0c;时间真的过得好快&#xff0c;总要写点什么留下纪念吧。这一年伴随着许多挑战和机会&#xff0c;给了我无数的成长和体验。坦白说&#xff0c;有时候我觉得自己好像是在时间的…

腾讯云4核8G服务器CVM标准型S5实例 S5.LARGE8性能测评

腾讯云4核8G服务器优惠价格表&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;阿腾云atengyun.com分享腾讯云4核8G服务器详细配置、优惠价格及限制条件&…

ssm基于java的网上手机销售系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本网上手机销售系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

OLED取模流程

1、Img2Lcd(222.ping->222) 1.1选择xxx.ping文件 1.2设置生成xxx.bmp文件 2、用PCtoLCD2002优化 2.1预显图像 2.2设置输出的字模数据 2.3生成了像素点378*8个 2.4至少需要2970个像素点 2.5像素点为什么是378*83024个&#xff1f;

基于谷歌模型gemini-pro 的开发的QT 对话项目

支持的功能&#xff0c;新建对话框&#xff0c;目前发现相关梯子不支持访问谷歌的api 的可能代理设置的不对&#xff0c; QNetworkAccessManager manager;// Set up your requestQNetworkRequest request;request.setUrl(QUrl("https://generativelanguage.googleapis.com…

使用 exec*库函数、编程练习动态链接库的两种使用方式

blog_week08 编程使用 exec*库函数加载一个可执行文件&#xff0c;编程练习动态链接库的两种使用方式一、 编程使用 exec*库函数加载一个可执行文件二、 编程练习动态链接库的两种使用方式 编程使用 exec*库函数加载一个可执行文件&#xff0c;编程练习动态链接库的两种使用方式…

git基础概念和常用命令(日常开发收藏备用)

目录 ### 常用命令 ### 远程仓库与克隆 ### 分支管理 ### 子模块&#xff08;Submodule&#xff09; ### 其他高级操作 ### 交互式暂存&#xff08;Interactive Staging&#xff09; ### cherry-pick ### rebase ### reflog与reset ### 子树合并&#xff08;Subtree …

分类模型评估方法

1.数据集划分 1.1 为什么要划分数据集? 思考&#xff1a;我们有以下场景&#xff1a; 将所有的数据都作为训练数据&#xff0c;训练出一个模型直接上线预测 每当得到一个新的数据&#xff0c;则计算新数据到训练数据的距离&#xff0c;预测得到新数据的类别 存在问题&…

vscode软件安装步骤

目录 一、下载软件安装包 二、运行安装包后 一、下载软件安装包 打开vscode官方网址&#xff0c;找到下载界面 链接如下&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 我是windows电脑&#xff0c;各位小伙伴自己选择合适的版本&#xff0c;点击下载按钮…

LVS负载均衡配置虚拟引起微服务注册混乱

线上小程序突然报错&#xff0c;查看网关日志&#xff0c;访问下游微服务A时大量报错&#xff1a; 1&#xff09;检查微服务是否未注册。登录eureka页面&#xff0c;发现三个节点均正常注册 三个微服务节点地址分别为&#xff1a;13.9.1.91:8080&#xff0c;13.9.1.92:8080和1…

Chapter 7 - 8. Congestion Management in Ethernet Storage Networks以太网存储网络的拥塞管理

Stomped CRC Counters Stomped CRC counters help in finding the location of bit errors in a network that uses cut-through switches. More precisely, these counters help in finding where bit errors do not exist. Stomped CRC 计数器有助于在使用直通式交换机的网络…

c语言-指针练习题

目录 前言一、题目一二、题目二总结 前言 为了巩固c语言中关于指针知识点的掌握&#xff0c;本篇文章记录关于指针的练习题。 一、题目一 有n个整数&#xff0c;使前面各数顺序往后移动m个位置&#xff0c;最后m个数变成最前面的m个数 写一函数实现以上功能&#xff0c;在主函…