关于电商秒杀系统中防超卖、以及高性能下单的处理方案简述

2023-11-16

在这里插入图片描述

秒杀抢购系统的成功平稳运行,有一些需要注意的知识点。

1 高并发,以及刷接口等黑客请求对服务端的负载冲击

2 高并发时带来的超卖,即商品数量的控制

3 高负载下,下单的速度和成功率的保证

4 其他

以秒杀单品为例,如抢小米手机。

解决方案探讨:

第一步 限制前端发来的请求量

譬如定在了周二10点开启抢购,那么在之前的一周时间内,都会有预约通知,或者普通的用户浏览。通过预约量、浏览量等数据分析,大概能预估到在周二会参与“点击抢购按钮”的人数。譬如有500万。

此时,我们是知道实际商品数量的,譬如20万。

那么我是没有必要让这500万个请求都到后台的,我最多最多放200万个请求到后台。其他的300万直接就在前端网页看单机动画就好了。

这一步做起来很简单,20万个商品,我提前生成200万个token,在用户点击预约、或者浏览该商品时,就按规则发放出去。(规则可以是譬如公平模式,某个用户id已经预约多次了,还没抢到,那么给他token。也可以就是随机发放,5天的预热时间,每天发4万个就好)

前端接收到是否能参与秒杀的反馈后,就保存在浏览器本地就好,当秒杀开始时,没得到token的用户,就只好在本地看单机动画,过几秒告诉他商品不足就好了。

那些幸运的得到了token的用户,就有了给后台发请求参加秒杀的机会了,此时还需要前端(APP客户端)来对请求进行控制,因为用户喜欢反复点击、反复刷新页面等手段来参加抢购,这时就不能再放重复请求进后台了,哪怕是他重复点击了,也要保证请求不反复发送。

对于大部分吃瓜群众来说,只会操作页面的就通过这种方式控制,但对于程序员们就不行了,即便是你在抢购开始前,没有暴露抢购的接口,但在抢购开始的一瞬间,他们依旧能搞到你的下单接口地址,并开始用程序频繁提交下单请求。

第二步 由网关限制程序过量请求

用程序下单对程序员们都懂,拼接好请求的各个参数,开启并发提交到服务器。

到了这一步,已经不归前端管了,请求会直达负载均衡器,然后到后台网关。

在网关里要控制好这部分请求,要以最快的速度判断出来的每一个请求是否放行到后面的服务。

网关的实现方案有很多,kong(nginx+lua),Gateway,zuul等。在网关里可以简单的实现限流机制,我们主要限制的有如下几种:

1 黑名单(ip、用户id等),可以直接放内存里

2 过多的重复请求(可以采用redis集群计数,对同一个ip、id发起的重复请求给予拒绝),考虑到redis的带宽、性能瓶颈,可以考虑做分片,或者做二级缓存,直接在jvm内存里统计计数

3 没有token的请求,就是之前放出去那批token

限制了非常规请求后,我们假如还有100万个请求在2秒内打到了服务端,这依旧是非常恐怖的数字,即便你有10台服务器,还是有大概率被打满CPU,后面的请求就有面临5秒超时的风险。

此时,我们要做的就是尽快处理完前面的请求,把商品赶紧卖光。100万个请求,20万个商品,那肯定是不能让那80万请求去触碰下单的服务的,我们要在网关处就终结掉这80万个请求,给他们交代你来晚了。

此时你需要令牌桶,如guava的rateLimer就可以,简单好用。譬如我有20个zuul网关服务在运行,单个服务要承担5万个请求,单个tomcat在不做复杂计算、不做数据库操作,做到1-2千的QPS还是可以的。

我每一个zuul服务里譬如开辟1.5万个令牌桶,在1-3秒内放完,得不到令牌桶的就直接返回失败就行了。在这一步失败的耗时会很短,因为在网关层就失败了,不会进入到后面的下单流程。

请注意,这一步是没有用消息队列的,因为大部分请求是要被拒绝的,需要尽快的返回拒绝信息,进队列再慢慢消费就慢了。

令牌桶签发完毕,剩下的请求都是幸运儿,就可以进入到后面的下单流程了。

第三步 极速下单

下单是另外的服务,由zuul将请求转发到这里,那么以最快的速度生成订单将非常重要,不然又是大量超时。

此时数据库是指望不上了,数据库一秒2千的写入都已经比较艰难,即便是集群,想要达到万的量级也是比较困难,等你入库完毕,都半分钟过去了。

那么下单到哪呢,首选redis。你在订单请求到达后,迅速拼接好order、orderItem对象,将订单下到redis里。考虑到redis的压力,可以将redis分片,将不同的用户的订单,下到不同的redis实例中。

下到redis的目的一是速度快,二是为了做订单查询用,因为下单后用户还是要查询订单的,而此时还没有入库。在下单到redis的同时,写入到消费队列MQ中一份,这一步是用来让后端消费,并入库的。入库就可以从MQ里慢慢消费了,再去做那些耗时的入库操作,分布式事务等等。入库成功后,就可以把redis的订单删掉了。

第四步 防超卖

从上面的流程看,我们通过令牌桶放出去的令牌数是大于商品数量的,那么就面临超卖问题。

超卖在分布式环境下,方案就是分布式锁,譬如redisson的分布式锁,可以针对商品id加分布式锁。

问题又出来了,如果商品数量很少,几百几千个,通过分布式锁也能很快的处理完。实测,redis加锁、释放锁耗时约1ms,再加上客户端逻辑处理时间,按下一单要5-10ms(非常急速了),那么一秒在对同一个分布式锁的操作上,也就百单而已。

可以发现,通过对同一个商品id加分布式锁,商品数量巨多时就麻烦了,因为是对商品id加锁,那么上锁解锁这个动作被执行几十万次,时间耗费巨大。

那么这个分布式锁就会有严重的性能问题,就要再次对商品数量进行分片,譬如一个用来分布式锁的redis key,只放500个商品数量,耗完结束,对应这个key的请求就算全部卖光。譬如商品id是10,那么我们就用goodsId-10-1,goodsId-10-2,goodsId-10-3这样,建立count/500个key,当请求来时,按照hash将分布式锁加到不同的key上。这样也能大幅提高分布式锁的性能。

当然这样会造成redis压力巨大,再将redis做个集群也行。总的来说这个方案貌似很复杂,而且很难控制,譬如比较难以控制不同key的余量消耗。

那么太复杂的方案就还是抛弃。我们直接在服务实例里写商品数量,这样直接在内存里判断商品剩余量,谁也不通信了,性能达到极致。

譬如我们部署了20个订单实例,20万个商品,我们将服务接入配置中心(Apollo,disconf,nacos之类的),通过配置中心来下发每个实例的商品数量,而且可以动态控制。可以在抢购开始前,通过配置中心下发到每个服务1万个商品数量,当这个实例将内存里的商品数量消耗完毕,就算售罄。当然,由于服务的处理速度,和请求的不均匀,可能导致某个实例早早售罄,别的实例还有大量剩余。也就是在页面上比你晚的人,来了还能买到,而你早早售罄了。那就不要怪程序员了。

要是中途个别实例挂掉了怎么办?挂掉了我们就不管它了。不要为它再设置什么复杂逻辑了。大不了少卖一些而已。既然是售罄,卖20万个,和卖了19万3千个,也没什么区别。可以等其他实例全卖光后,统计一下redis的订单数量,譬如卖了19万个3千,再把它启动起来,设置个7000的剩余量,这样也行。但这不重要了。可以将这部分放到30分钟后,没付款的被丢回库存池里再卖也一样。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于电商秒杀系统中防超卖、以及高性能下单的处理方案简述 的相关文章

  • 用Java将图像添加到数据库

    我正在尝试将图像添加到 mysql 数据库中的 BLOB 字段 图像大小将小于 100kb 但是我遇到了问题 想知道将这些数据添加到数据库的更好方法是什么 com mysql jdbc MysqlDataTruncation 数据截断 第
  • Cassandra Pojo Sink Flink 中的动态表名称

    我是 Apache Flink 的新手 我正在使用 Pojo Sink 将数据加载到 Cassandra 中 现在 我在以下命令的帮助下指定表和键空间名称 Table注解 现在 我想在运行时动态传递表名称和键空间名称 以便可以将数据加载到用
  • ProcessBuilder 未正确执行 Java 类文件

    在一个java文件中 我调用命令行语句来执行另一个java文件 这就是我正在做的 List
  • 为什么这不会绘制图像?

    我想做的是 当我运行应用程序时 它会启动线程并且图像显示 3 秒 3000 毫秒 然后线程停止运行 图片路径正确 图片文件存在 线程本身运行 但是 图像似乎没有显示 可能出什么问题了 这是我的代码 package org main impo
  • iText7:如何获取段落的实际宽度

    在添加到文档之前 我需要知道段落的宽度 以磅为单位 我在这里搜索并找到了 Alexey 关于段落高度的答案 所以我用宽度做了它 但它不起作用 无论段落有多长 始终返回矩形的宽度 我尝试了这段代码 private float getRealP
  • Encog - 如何加载神经网络的训练数据

    The NeuralDataSet我在实际中看到的对象除了 XOR 之外什么都没有 它只是两个小数据数组 我无法从文档中找出任何内容MLDataSet 似乎所有内容都必须立即加载 但是 我想循环遍历训练数据 直到到达 EOF 然后将其算作
  • 如何使 java.text.NumberFormat 将 0.0d 格式设置为“0”而不是“+0”?

    需要带符号的结果 0 0d 除外 IE 123 45d gt 123 45 123 45d gt 123 45 0 0d gt 0 我调用format setPositivePrefix 在 DecimalFormat 的实例上 强制结果中
  • 如何在 Java 中用 \n 替换 \\n

    我有一个string test first n middle n last 现在我想更换所有 n by n 我试过了test replaceAll n n and test replaceAll n n 但它们不起作用 有人有解决办法吗 T
  • 设置 MetaspaceSize 的指南 - java 8

    64 位服务器的 MetaspaceSize 默认值是多少 我在官方文档中没有找到它 我观察到 在服务器 JVM 进程中 GC 频率有时会变高并持续增长 如果我重新启动服务几次 它就会恢复稳定 我认为这是由于 JRE 升级造成的 JVM 堆
  • javax.el.PropertyNotFoundException:在 java.lang.String 类型上找不到属性“tname”

    我之前使用的是 scriptlet 但现在我改用了 mvc 我无法检索 JSP 页面上的值并收到错误 javax el PropertyNotFoundException Property tname not found on type j
  • 将 Spring ModelAttribute 应用于所有使用特定参数类型的控制器

    在 Spring Boot REST 应用程序中 我有一个TableRequest包含表格数据 GET 请求的列排序 筛选和分页详细信息的类型 它是通用的 因为它不关心所请求的具体数据是什么 它只指定通用表参数 因此它适用于许多不同的控制器
  • 飞碟中的外部 CSS

    我想知道如何在 Flying Saucer 中包含外部 CSS 在此之前THB我检查了所有可用的链接StackOverflow但它们没有帮助 这就是为什么我自己做这个的原因 TestCSS xhtml重命名版本TestCSS html 所以
  • Android 改造参数化@Headers

    我正在使用 OAuth 每次发出请求时都需要将 OAuth 令牌放入标头中 我看到 Header注释 但是有没有办法让它参数化 以便我可以在运行时传入 这是概念 Header Authorization OAuth var api vers
  • 如何在打开导航抽屉时使背景 Activity 变小?

    我想做我的背景Activity打开时稍微小一点Navigation Drawer 模拟存在的效果Airbnb应用 我想最好的解释是截图 但重点不是让 View 变小 而是让它成为与 Drawer 打开 关闭动画同步的动画 因此 如果您开始打
  • 将 try catch finally 块放入另一个 finally 块中

    try catch finally try catch finally 上面的代码好不好 是的 你可以这样做 实际上 在处理想要正确关闭的流时 您甚至需要这样做 InputStream in try catch finally try in
  • 用于验证 InetSocketAddresses 的正则表达式(ipv4/v6 + 端口地址)

    我在寻找testedipv4 和 ipv6 的正则表达式InetSocket地址 http download oracle com javase 6 docs api java net InetSocketAddress html toSt
  • java.lang.NoClassDefFoundError: org/apache/commons/cli/ParseException

    我想将 apache cli 添加到我的应用程序中 但我有问题 当我尝试运行它时显示这些错误 Error A JNI error has occurred please check your installation and try aga
  • 表达式的类型必须是数组类型,但它解析为浮点数

    当我编写 Java 代码时 我遇到了困难 我觉得我不知何故把这个概念弄乱了 就像我不确定这一点 void setScore float sco sco score public void setScore float sco int id
  • 注释处理工具<-检查有效注释

    I have ColumnMetadata index 1 ColumnMetadata index 2 ColumnMetadata index 3 我必须使用 APT 检查索引号是否唯一 我不知道该怎么做 我看不懂教程 一般我在网上找资
  • 如何在 Android 上设置 Google Drive API?

    我一直在尝试将 Google Drive 功能集成到我的应用程序中 但我无法使用任何内置功能 因此我相信我要么错过了一个步骤 要么做得不正确 我正在遵循官方的 Google 开发者指南 https developers google com

随机推荐

  • 小白上路~微信小程序登录授权无法获取用户信息

    1 button 标签和 open type getUserInfo 获取用户信息失败 天哪噜 必须好好记录一番由于没有看官方文档更新 api 而导致的 BUG 一觉醒来 发现准备收尾的小程序无法获取到用户信息了 怎么回事 于是一顿焦虑 骚
  • CodeWhisperer 初体验

    今年算是 AI 正式破圈的一年 无数的工具 产品横空出世 无论在面向企业的大语言模型 还是帮助个人的 AI 工具 数不胜数 其中关于 AI 编程助手领域 近年来也涌现了很多不错的产品 例如 Copilot Cursor 还是我们今天要体验的
  • 【转】在iPad的Safari上查看HTML源代码

    在网上搜索的文章 转来转去 基本上都缺少了关键脚本 所以写在这了 使用方法 1 随便保存一个书签 名称就叫查看源码之类的就好了 2 编辑该书签 删除原网址 将下面的脚本黏贴到网址中 3 在你想要查看源码的页面点击该书签 源码就出现了 jav
  • 【Pytorch】第 1 章 :强化学习和 PyTorch 入门

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • html网页的基本标签

    1 标题标签 h1 一级标签 h1 h2 二级标签 h2 h3 三级标签 h3 h4 四级标签 h4 h5 五级标签 h5 2 段落标签 p 民办清华 建校三十周年 p p okok p 3 换行标签 4 水平线标签 5 字体样式标签 st
  • python写水仙花数

    水仙花数是指一个n位数 n gt 3 他的每个位上 的数字的n次幂之和等于他本身 例1 3 5 3 求1000以内的水仙花数 i 100 while i lt 1000 a i 100 b i 10 10 c i 10 if a 3 b 3
  • FPGA学习日记(五)ZYNQ——在线逻辑分析仪(ILA)硬件调试及simulator仿真软件的创建使用

    一 在线逻辑分析仪 ILA vivado的在线逻辑分析仪 ILA 其借用了传统逻辑分析仪的理念以及大部分的功能 并利用 FPGA 中的逻辑资源 将这些功能植入到 FPGA 的设计当中 如下图所示 ILA占用一部分FPGA内部逻辑资源 可看做
  • 运算放大器的关键指标详解二(噪声)

    1 噪声指标 Noise 一个正常工作的放大电路 当输入端接地时 用示波器观察输出 你看到的可能不是平直的细线 而是在一定幅度之内的杂乱无章的波形 这就是噪声 你在示波器上看到线越粗 就说明噪声幅度越大 放大电路的输出端噪声 小至 V 以下
  • redis客户端Jedis和Lettuce

    Jedis和Lettuce的区别 Jedis是同步的 不支持异步 Jedis客户端实例不是线程安全的 需要每个线程一个Jedis实例 所以一般通过连接池来使用Jedis Lettuce是基于Netty框架的事件驱动的Redis客户端 其方法
  • 12、剪绳子——剑指offer——动态规划

    剪绳子 问题描述 给你一根长度为n的绳子 请把绳子剪成m段 m和n都是整数 n gt 1并且m gt 1 每段绳子的长度记为k 0 k 1 k m 请问k 0 k 1 k m 可能的最大乘积是多少 首先本题可以用贪婪算法和动态规划算法求解
  • VLC在Android中的使用以及vlc中options的参数

    options 中的参数 我在csdn中找过很多篇文章了 有的文章一个参数也没写 有的写的都是关于缓存的 还有的写了几个 也没说明是什么意思 然后只能跑到csdn下载文档查看 为了方便网友们的使用 这里就简单写一下我是怎么使用的 后面会附上
  • Flink-cdc 同步mysql数据

    下载地址 https github com ververica flink cdc connectors releases 这里下载2 2 0版本 https github com ververica flink cdc connector
  • 搭建RocketMq(超详细,图文并茂)

    环境 jdk 1 8 rocketMq 版本 4 5 1 rocketmq all 4 5 1 bin release zip 附上链接 小伙伴自行下载 链接 https pan baidu com s 1zyzF3uZ3YN0YWzcLt
  • Linux脚本练习之script092- 判断输入的是否为IP地址

    script092 题目 注 题目来源于 SHELL16 判断输入的是否为IP地址 写一个脚本统计文件nowcoder txt中的每一行是否是正确的IP地址 如果是正确的IP地址输出 yes 如果是错误的IP地址 四段号码的话输出 no 否
  • SPECjbb 分析与使用

    SPECjbb 分析与使用 一 目的 二 SPECjbb 简介 2 1 是什么 2 2 三层客户 服务器模型结构 2 3 特性 三 环境说明 四 TPC C 简介 4 1 是什么 4 2 TPC C模型 4 3 TPC C指标 4 4 TP
  • dword ptr指令讲解

    dword ptr指令讲解 8086CPU的指令 可以处理两种尺寸的数据 byte和word 所以在机器指令中要指明 指令进行的是字操作还是字节操作 对于这个问题 汇编语言中用一下方法处理 1 通过寄存器名指明要处理的数据的尺寸 例如 下面
  • linux配置交换内存(虚拟内存)

    虚拟内存 Virtual Memory 是操作系统内存管理的一种技术 它将主存虚拟化 使得程序可以获得更大的可用内存空间 虚拟内存的主要优点有 提高内存利用率 可以加载更大的程序到内存中执行 提供了内存保护 避免程序间相互干扰 实现了懒加载
  • 【FPGA多周期约束】

    多周期约束及语法 一 什么时候需要用到多周期约束 Vivado TimeQuest等时序引擎默认是按照单周期关系分析数据关系的 即数据在发起沿发送 在捕获被捕获 发起沿和捕获沿相差一个周期 但是很多情况是 数据路径逻辑较为复杂 导致延时较大
  • 朴素贝叶斯基本原理和预测过程、先验概率、后验概率、似然概率概念

    贝叶斯原理是英国数学家托马斯 贝叶斯提出的 贝叶斯原理 建立在主观判断的基础上 在我们不了解所有客观事实的情况下 同样可以先估计一个值 然后根据实际结果不断进行修正 举例 一个袋子里有10个球 其中6个黑球 4个白球 那么随机抓一个黑球的概
  • 关于电商秒杀系统中防超卖、以及高性能下单的处理方案简述

    秒杀抢购系统的成功平稳运行 有一些需要注意的知识点 1 高并发 以及刷接口等黑客请求对服务端的负载冲击 2 高并发时带来的超卖 即商品数量的控制 3 高负载下 下单的速度和成功率的保证 4 其他 以秒杀单品为例 如抢小米手机 解决方案探讨