当前位置:首页 > 架构 > 正文内容

秒杀如何设计

phpmianshi2年前 (2019-04-06)架构280

秒杀难点:

1、突发流量、数据热点

2、数据一致性、短暂混沌态
如果采用传统的数据库进行数据存储,对同一资源的争抢,就会面临严重的锁冲突问题。一般是通过一个前置的,速度更快的存储顶在前面,这就涉及到源库和目标库的数据同步问题。

从商品资源的上架,到秒杀的完成,会经历一个短暂的混沌状态,出现数据不一致的情况。在请求量非常集中的情况下,还会产生并发问题,个体的行为和结果,是不可预测的。

系统层面,秒杀业务如何设计?

  • 客户端,app或者浏览器

  • 站点层,访问后端数据

  • 服务层,屏蔽底层数据细节,提供数据访问

  • 数据层,DB存储库存,当然也有缓存

这四层分别应该如何优化呢?

一、客户端上的请求拦截

1.可以限制用户在n秒之内只能提交一次请求

2.点击以后按钮变为不可点击状态

3.增加倒计时等

4.浏览器缓存,增加秒杀答题,防止有秒杀器


二、站点层的设计

秒杀类业务都需要登录,用uid就能标识用户

在站点层,对同一个uid的请求进行计数和限速,例如:一个uid,5秒只准透过1个请求,这样又能拦住99%的循环请求。

一个uid,5s只透过一个请求,其余的请求怎么办?

缓存,页面缓存,5秒内到达站点层的其他请求,均返回上次返回的页面。

假设真实有效的请求数是每秒100w,这部分的压力怎么处理?

解决方向有两个:

(1)站点层水平扩展,通过加机器扩容,一台抗5000,200台搞定;

(2)服务降级,抛弃请求,例如抛弃50%;

站点层限速,是个每个uid的请求计数放到redis里么?吞吐量很大情况下,高并发访问redis,网络带宽会不会成为瓶颈?

同一个uid计数与限速,如果担心访问redis带宽成为瓶颈,可以这么优化:

(1)计数直接放在内存,这样就省去了网络请求;

(2)在nginx层做7层均衡,让一个uid的请求落到同一个机器上;

系统隔离
秒杀业务占用的系统资源,和正常运行的系统严重不对等。如果有条件,秒杀系统的硬件和服务环境,要与正常业务系统进行一定程度的隔离。要提前评估对其他服务的压力,避免影响正常业务。

CDN
对于html,js,css,图片等内容,占用了大量的带宽。如果将这些资源都放在自己的服务器上,流量到来时会迅速占满带宽,造成正常的秒杀请求无法完成。CDN可以有效解决这个问题。剩下的请求,就是真正的秒杀业务。

减小请求包
对网络请求包,要进行大量优化。可以开gzip压缩,资源本身也进行压缩,去掉请求包中的无用信息,对网络报文进行精简。

三、服务层的设计

并发的请求已经到了服务层,如何进拦截?

服务层非常清楚业务的库存,非常清楚数据库的抗压能力,可以根据这两者进行削峰限速。

例如,业务服务很清楚的知道,一个商品的秒杀总共只有100个商品,此时透传10w个请求去数据库,是没有意义的。


用什么削峰?

请求队列。

对于写请求,做请求队列,每次只透传有限的写请求去数据层。


只有100个商品,即使10w个请求过来,也只透传100个去访问数据库:

  • 如果前一批请求均成功,再放下一批

  • 如果前一批请求秒杀结束,则后续请求全部返回“秒杀完成”


对于读请求,怎么优化?

cache抗,不管是memcached还是redis,单机抗个每秒10w应该都是没什么问题的。

如此削峰限流,只有非常少的写请求,和非常少的读缓存mis的请求会透到数据层去,又有99%的请求被拦住了。

可以对秒杀产品做数据预热

安全

要尽量提高作弊门槛,比如url动态化;验证码,只会增加攻击者的成本。有些安全性级别较高的,还会增加风控规则,比如同一ip请求过多封禁、账号注册日期三天之内不允许参与、秒杀的门槛必须是金牌会员等。

秒杀前5分钟,验证码升级等。

四、数据库层

经过前三层的优化:

  • 客户端拦截了80%请求

  • 站点层拦截了99%请求,并做了页面缓存

  • 服务层根据业务库存,以及数据库抗压能力,做了写请求队列与数据缓存

你会发现,每次透到数据库层的请求都是可控的。


解决超卖

1. 在系统初始化时,将商品的库存数量加载到Redis缓存中;

2. 接收到秒杀请求时,在Redis中进行预减库存,当Redis中的库存不足时,直接返回秒杀失败,否则继续进行第3步;

3. 减掉库存后,下单请求放入异步队列中,返回正在排队中;

4. 服务端异步队列将请求出队,出队成功的请求可以生成秒杀订单,返回秒杀订单详情。

5. 用户在客户端申请秒杀请求后,进行轮询,查看是否秒杀成功,秒杀成功则进入秒杀订单详情,否则秒杀失败。

6. 预留支付时间,超时未支付库存恢复,可以继续购买


解决库存热点key问题

1. 利用二级缓存

比如利用ehcache,或者一个HashMap都可以。把热key加载到系统的JVM中。
针对这种热key请求,会直接从jvm中取,而不会走到redis层。
假设此时有十万个针对同一个key的请求过来,如果没有本地缓存,这十万个请求就直接怼到同一台redis上了。
现在假设,你的应用层有50台机器,OK,你也有jvm缓存了。这十万个请求平均分散开来,每个机器有2000个请求,会从JVM中取到value值,然后返回数据。避免了十万个请求怼到同一台redis上的情形。

2. 备份热key
这个方案也很简单。不要让key走到同一台redis上不就行了。我们把这个key,在多个redis上都存一份不就好了。接下来,有热key请求进来的时候,我们就在有备份的redis上随机选取一台,进行访问取值,返回数据。


分享一个比较好的视频讲解:

https://www.imooc.com/video/19875


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

如何实现分布式事务

事务定义简单地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。数据库本地事务数据库事务中的四大特性 ACIDA:原子性(Atomicity),一个事务(transa...

基于rebase的Git工作流

使用Git在多人协作的过程中,我们也会面临如何运用好Git的问题。这种情况下,就出现了各种各样的Git Workflow,而本文将介绍一种基于rebase的工作流,这种工作流也是目前开源社区所比较推崇...

大型系统高可用的一般策略

负载均衡首先是应用服务器的负载均衡。负载均衡核心要解决的就是通过一个负载均衡服务器,将用户的请求分发给多个应用服务器,将多个应用服务器构建成一个集群,共同对外提供服务。这样的架构可以提高系统的处理能力...

互联网应用可用性的度量

概念业界通常用多少个 9 来说明互联网应用的可用性。示例比如说 QQ 的可用性是 4 个 9,就是说 QQ 的服务 99.99% 可用,这句话的意思是 QQ 的服务要保证在其所有的运行时间里只有 0....

如何应对网站流量暴增

如何应对网站流量暴增

按照经验大概出问题地方是DB,磁盘io、CPU、带宽、连接数、内存其中的一个或几个。不同的业务,不同的系统设计,出问题的地方会有所不同。如果流量增大数倍,势必某个资源会在瞬间被榨干,然后所有的服务都会...

系统架构的演进之路-单体到SOA到微服务

单体系统的困难在微服务出现之前,互联网应用系统主要是单体系统,也就是说一个网站的整个系统由一个应用构成。如果是 Java,就打包成一个 war 包,一个 war 包包含整个应用系统,系统更新的时候,即...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。