高并发下秒杀系统的设计
打个小广告
我的架构设计专栏: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等私密数据。比如说:
- 很多媒体类的网站,某一篇文章的内容不管是你访问还是我访问,它都是一样的。所以它就是一个典型的静态数据,但是它是个动态页面。
- 我们如果现在访问淘宝的首页,每个人看到的页面可能都是不一样的,淘宝首页中包含了很多根据访问者特征推荐的信息,而这些个性化的数据就可以理解为动态数据了。
2.秒杀按钮前端限流
通过前端的计时器与按钮状态来避免用户连续点击发送大量请求。
在秒杀系统中,为了避免用户连续点击秒杀按钮而发送大量请求,前端可以通过计时器结合按钮的状态控制来实现这一功能。下面是一个简化的步骤说明和示例代码,展示如何实现这一机制:
步骤说明
- 初始化秒杀按钮状态:秒杀按钮初始是可用的。
- 设置倒计时:使用JavaScript的
setInterval
函数来创建一个定时器,每隔一定时间(通常是1秒)更新倒计时。 - 禁用秒杀按钮:当用户点击秒杀按钮后,立刻禁用该按钮(按钮变灰),并开始倒计时。
- 倒计时结束:当倒计时结束时,重新启用秒杀按钮,并清除定时器。
3.读多写少(缓存+读写分离)
在秒杀的过程中,系统一般会先查一下库存是否足够,如果足够才允许下单,写数据库。如果不够,则直接返回该商品已经抢完。
由于大量用户抢少量商品,只有极少部分用户能够抢成功,所以绝大部分用户在秒杀时,库存其实是不足的,系统会直接返回该商品已经抢完。
这是非常典型的:读多写少
的场景。
缓存+读写分离
4.缓存问题
缓存击穿(缓存没有数据库有)缓存预热+分布式锁
比如商品A第一次秒杀时,缓存中是没有数据的,但数据库中有。虽说上面有如果从数据库中查到数据,则放入缓存的逻辑。
然而,在高并发下,同一时刻会有大量的请求,都在秒杀同一件商品,这些请求同时去查缓存中没有数据,然后又同时访问数据库。结果悲剧了,数据库可能扛不住压力,直接挂掉。
当然,针对这种情况,最好在项目启动之前,先把缓存进行预热
。即事先把所有的商品,同步到缓存中,这样商品基本都能直接从缓存中获取到,就不会出现缓存击穿的问题了。
是不是上面加锁这一步可以不需要了?
表面上看起来,确实可以不需要。但如果缓存中设置的过期时间不对,缓存提前过期了,或者缓存被不小心删除了,如果不加速同样可能出现缓存击穿。
其实这里加锁,相当于买了一份保险。
- 解决方法
缓存预热+分布式锁
缓存穿透(数据库缓存都没有)布隆过滤器/对不存在元素进行缓存
如果
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
我的笔记专栏,内有自己整理的八股知识笔记和算法刷题笔记,我会不断通过他人和自己的面经来更新和完善自己的八股笔记。专栏每增加一篇文章费用就会上涨一点,如果你喜欢的话建议你尽早订阅。内有超详细苍穹外卖话术!后续还会更新其他项目和我的实习经历的话术!敬请期待!