高并发下秒杀系统的设计

打个小广告

我的架构设计专栏:https://www.nowcoder.com/creation/manager/columnDetail/0ybvLm

我的java八股专栏:https://www.nowcoder.com/creation/manager/columnDetail/j8ZZk0

内有详细苍穹外卖话术哦!

欢迎订阅!

0.前言

秒杀系统主要有这几个特征:

  • 瞬时间的流量特别高。过了秒杀的时间,流量就会瞬时结束
  • 大批量用户同时请求极少数商品
  • 在秒杀时间前,可能会有很多请求过来。比如在11点抢票开始,10点59分你可能会提前去刷新页面请求。

秒杀系统要注意的细节:

瞬时高并发

一般在秒杀时间点(比如:12点)前几分钟,用户并发量才真正突增,达到秒杀时间点时,并发量会达到顶峰。

但由于这类活动是大量用户抢少量商品的场景,必定会出现狼多肉少的情况,所以其实绝大部分用户秒杀会失败,只有极少部分用户能够成功。

正常情况下,大部分用户会收到商品已经抢完的提醒,收到该提醒后,他们大概率不会在那个活动页面停留了,如此一来,用户并发量又会急剧下降。所以这个峰值持续的时间其实是非常短的,这样就会出现瞬时高并发的情况。

0.架构设计

1.前端页面静态化+CDN

活动页面是用户流量的第一入口,所以是并发量最大的地方。

如果这些流量都能直接访问服务端,恐怕服务端会因为承受不住这么大的压力,而直接挂掉。

活动页面绝大多数内容是固定的,比如:商品名称、商品描述、图片等。为了减少不必要的服务端请求,通常情况下,会对活动页面做静态化处理。用户浏览商品等常规操作,并不会请求到服务端。只有到了秒杀时间点,并且用户主动点了秒杀按钮才允许访问服务端。

这样能过滤大部分无效请求。

但只做页面静态化还不够,因为用户分布在全国各地,有些人在北京,有些人在成都,有些人在深圳,地域相差很远,网速各不相同。

如何才能让用户最快访问到活动页面呢?

这就需要使用CDN,它的全称是Content Delivery Network,即内容分发网络。

使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

什么是CDN?

CDN,即内容分发网络(Content Delivery Network),是一种构建在现有网络基础之上的智能虚拟网络,旨在通过全球分布的边缘服务器为用户提供所需内容的就近获取服务。

CDN的全称是Content Delivery Network,即内容分发网络。CDN通过在全球各地部署边缘服务器,利用中心平台的负载均衡、内容分发和调度功能模块,使用户能够就近获取所需内容,降低网络拥塞,提高访问响应速度和命中率。CDN的关键技术包括内容的存储和分发技术,它通过将内容缓存到网络边缘的节点上,从而使用户在上网时不必直接访问源站,而是访问离他最近的一个CDN节点,实现快速获取数据。

什么是动静数据?

简单来说, “动态数据”和“静态数据”的主要区别就是看页面中输出的数据是否和URL、浏览者、时间、地域相关,以及是否含有Cookie等私密数据。比如说:

  1. 很多媒体类的网站,某一篇文章的内容不管是你访问还是我访问,它都是一样的。所以它就是一个典型的静态数据,但是它是个动态页面。
  2. 我们如果现在访问淘宝的首页,每个人看到的页面可能都是不一样的,淘宝首页中包含了很多根据访问者特征推荐的信息,而这些个性化的数据就可以理解为动态数据了。

2.秒杀按钮前端限流

通过前端的计时器与按钮状态来避免用户连续点击发送大量请求。

在秒杀系统中,为了避免用户连续点击秒杀按钮而发送大量请求,前端可以通过计时器结合按钮的状态控制来实现这一功能。下面是一个简化的步骤说明和示例代码,展示如何实现这一机制:

步骤说明

  1. 初始化秒杀按钮状态:秒杀按钮初始是可用的。
  2. 设置倒计时:使用JavaScript的setInterval函数来创建一个定时器,每隔一定时间(通常是1秒)更新倒计时。
  3. 禁用秒杀按钮:当用户点击秒杀按钮后,立刻禁用该按钮(按钮变灰),并开始倒计时。
  4. 倒计时结束:当倒计时结束时,重新启用秒杀按钮,并清除定时器。

3.读多写少(缓存+读写分离

在秒杀的过程中,系统一般会先查一下库存是否足够,如果足够才允许下单,写数据库。如果不够,则直接返回该商品已经抢完。

由于大量用户抢少量商品,只有极少部分用户能够抢成功,所以绝大部分用户在秒杀时,库存其实是不足的,系统会直接返回该商品已经抢完。

这是非常典型的:读多写少 的场景。

缓存+读写分离

4.缓存问题

缓存击穿(缓存没有数据库有)缓存预热+分布式锁

比如商品A第一次秒杀时,缓存中是没有数据的,但数据库中有。虽说上面有如果从数据库中查到数据,则放入缓存的逻辑。

然而,在高并发下,同一时刻会有大量的请求,都在秒杀同一件商品,这些请求同时去查缓存中没有数据,然后又同时访问数据库。结果悲剧了,数据库可能扛不住压力,直接挂掉。

当然,针对这种情况,最好在项目启动之前,先把缓存进行预热。即事先把所有的商品,同步到缓存中,这样商品基本都能直接从缓存中获取到,就不会出现缓存击穿的问题了。

是不是上面加锁这一步可以不需要了?

表面上看起来,确实可以不需要。但如果缓存中设置的过期时间不对,缓存提前过期了,或者缓存被不小心删除了,如果不加速同样可能出现缓存击穿。

其实这里加锁,相当于买了一份保险。

  • 解决方法

缓存预热+分布式锁

缓存穿透(数据库缓存都没有)布隆过滤器/对不存在元素进行缓存

如果

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

内容包含: 1.后端八股大全:多一句没有少一句不行的最精简八股整理,完全可以应付校招八股拷打! 2.速成项目话术:目前有魔改苍穹外卖项目话术(额外扩展了很多技术亮点),能速成拿去面试,后面会更新agent开发等等热门高质量项目话术 3.智力题超详细题解汇总; 4.面试时非技术问题话术整理,绝对震惊面试官一年; 5.算法lc hot100全题系列题解:绝对通俗易懂。 欢迎订阅!

全部评论
又被牛客禁言60天,刚申诉放出来就发了这篇文章,喜欢的朋友给我点点赞吧!
9 回复 分享
发布于 2024-08-01 22:46 广东
帅😍
2 回复 分享
发布于 2024-11-21 23:18 湖北

相关推荐

04-09 13:59
吉林大学 Java
问题 1 请先做个简单的自我介绍,并详细说说你在项目中是如何利用Redis和消息队列处理高并发抢券/秒杀场景的?问题 2你在项目中使用的分布式锁经历了怎样的演进过程?请结合JMeter的压测数据,谈谈最初的Redisson方案是如何实现一人一单的,以及它是怎么处理超卖回滚的?问题 3请详细解释一下Redisson分布式锁中的“看门狗(Watchdog)”机制是如何工作的?它的触发条件和底层续期逻辑是什么?问题 4如果不直接使用Redisson,让你自己手动编码实现一个类似“看门狗”的自动续期机制,你会怎么设计这套逻辑?问题 5既然Redis本身支持设置Key的过期时间,那我们为什么不能直接依赖这个自动过期时间来释放分布式锁?完全依赖超时自动释放会有什么隐患?问题 6在预扣减Redis库存成功后,如果由于网络故障或RabbitMQ宕机导致消息发送失败,数据库没有成功落库,这种情况下的数据不一致问题你是如何保证兜底解决的?问题 7你提到方案经过了优化,请问从纯分布式锁优化为Lua脚本方案后,系统的QPS具体提升了多少?性能翻倍的根本原因是什么?问题 8使用Lua脚本嵌入Redis执行确实能大幅提升并发性能,但在工程实践中,编写和维护Lua脚本存在哪些弊端或需要注意的风险?问题 9你提到项目中大量使用了MyBatis Plus,那么请问MyBatis底层是如何防止SQL注入的?它的核心原理机制是什么?问题 10在使用MyBatis Plus进行数据分页查询时,它的物理分页底层是如何实现的?拦截器(Interceptor)在这里起到了什么核心作用?问题 11框架在进行物理分页时,具体的分页参数(如当前页码、每页大小)在应用层和底层之间是如何封装和传递的?问题 12除了MyBatis Plus,你平时还会去主动研究哪些主流框架的底层源码?能分享一下你最熟悉的框架源码机制吗?问题 13当你在项目中需要引入一个新的中间件或技术栈时,你的学习和落地路径是怎样的?你会如何平衡AI辅助工具和官方文档的使用?问题 14在日常开发排错和遇到复杂的系统性能瓶颈时,你通常会如何利用AI工具?有什么核心决策是你绝对不会完全交由AI去决定的?问题 15你在设计分布式锁的Key时,曾和AI的建议产生过分歧。请结合具体的业务安全场景(如防黑产刷单),谈谈你是如何权衡纯粹的“技术并发度”与真实的“业务安全性”的?问题 16结合你的项目开发经验,谈谈你为什么深度依赖Spring Boot框架?它的核心设计优势(例如自动装配)在底层是如何实现的?问题 17请深入讲解一下Spring的IOC容器是如何管理Bean的生命周期的?特别是遇到带有AOP增强的循环依赖时,三级缓存是如何精妙运作来解决这个死循环问题的?问题 18在处理系统中大量重复的公共字段(如创建时间、更新人)时,你是如何利用自定义注解结合Spring AOP和反射机制,实现无侵入式自动填充的?算法题用java实现lru
查看20道真题和解析
点赞 评论 收藏
分享
04-10 17:12
已编辑
重庆大学 Java
1.自我介绍2.如何学习java,是通过学校课程学习还是自学的?3.用户登录校验是如何做的?4.你说用redis对活跃的token实现刷新过期时间,这个功能你是如何实现的?5.频繁的时间戳更新会不会导致redis大量的内存被占用,想别的方案来解决6.redis对key值的过期策略是怎样的?8.介绍你的缓存更新策略吧(我提到redis中的cache Aside策略,补充了消息广播实现本地缓存数据一致性,利用kafka中不同消费组订阅同一topic实现消息广播,某一节点删除缓存时,其他节点都删除本地缓存,从而实现分布式系统本地缓存的一致性)7.JVM中垃圾回收(GC)的策略是怎样的?9.你使用了Redisson实现分布式锁,请解释一下Redisson分布式锁中的看门狗机制10.解释一下Mybatis如何防止sql注入,MybatisPlus中是如何将方法映射为sql的11.你使用了Shardingsphere进行分库分表,那Shardingsphere的底层是怎样的呢11.再介绍一下你项目中的亮点吧(定时对账:在kafka宕机时进行埋点,记录日志。恢复后回滚到之前的库存状态;延迟队列:使用Redisson的延迟队列,为业务设定一个延迟的时间执行)12.你另外一个项目中的Agent是如何设计的13.详细讲讲离线上传中长文本如何分块,固定分块有什么劣势,你如何设计分块方案(面试官补充了语义网络的概念)算法LRU职业规划方向反问面试官人很好,比较看重你实际项目开发中对使用过的技术栈的底层原理的理解以及业务的设计
查看16道真题和解析
点赞 评论 收藏
分享
前几天这下午那场面试真的是有史以来面试体验感最差的一次。本来这个职位和我就不是同一个领域的,我是做游戏的,你做短剧的来招我,所以我个人意向本来就不大,但hr昨天疯狂追着我,要给我安排面试才有了这一场面试。这是我第一次参加微信群面试,四个人面我一个。约的下午1:30,她们公司的面试官晚了10分钟才进入会议室,hr介绍说他是什么什么总,所以我也礼貌性的随着一起叫的什么什么总。上来之后让我自我介绍,完了之后就开始他的表演了。程高高在上的态度,语气中全程带着嘲讽和贬低的意思,说我做的这个工作谁都能做,你的价值是什么?完全没看到你的价值。我礼貌回答了我觉得自己做的有价值的地方,他就开始疯狂diss 说你觉得自己做的这个事情成果好吗?我说我觉得我做的成果挺好的。接下来就是无尽的质疑和贬低的话,面到一半我真的气的想甩手机走了,但是由于第一次遇到这种情况不知道怎么办只是很气的状态,所以出于礼貌没有打断面试的进行,最后我真的面不下去了,他问我还有什么问题吗?我说没了,然后他就开始让其他面试官问我,其他面试官还是挺礼貌的,所以我也礼貌回答了,面试就结束了。嗷对了,微信群面试的时候就让我一个人开了摄像头,其他几个面试官都没开。一点小建议:面试本质是双向选择,对方不尊重你,也暴露了他们的团队文化。遇到这种情况,不用急着怼回去,像你一样冷静记录、面试结束后礼貌反馈给HR,已经很得体了。下次可以提前确认:面试官是否开摄像头?面试领域是否匹配?能筛掉不少坑。记住:不是你不够好,是对方不配。
muf:这个工作谁都能做,你的价值是什么? 如果是我就先否定他,告诉他首先这个工作不是谁都能做,需要什么什么能力和特质,其次是即使有部分人也都能做,但是人和人是有区别的,我做的质量、效果就是比其他人好,最后是即便有些人能做,也不代表我做了就没有价值,美国能造原子弹,朝鲜也能造原子弹,难道说明造原子弹这个事情没有技术含量吗?
面试体验最好和最差的公司
点赞 评论 收藏
分享
评论
14
41
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务