赣州新闻网

首页 / 科技

掌握这些,高并发秒杀系统就不用担心了!

2020-04-13 · 赣州新闻网 · 科技

很多小伙伴反馈说,高并发专题学了那么久,但是,在真正做项目时,仍然不知道如何下手处理高并发业务场景!

掌握这些,高并发秒杀系统就不用担心了!

图片来自 Pexels

甚至很多小伙伴仍然停留在只是简单的提供接口i 9 4 Y $(CRUD)阶段,不知道学习的并发知识如何运用到实际项目中,就更别提如何构建高并发系统了!

究竟什么m R V ~ M 样R a D N W Q原来的价格出售。

例如,秒杀活动的时间仅_ } T限于某天上午 10 点到 1f | S0 点半,商品数* a 8 ~ 1 i 3 0 `量只有 10 万件,售完为止,而且商品的价格非常低,例如:1 元购等业务场景。

限时、限量和限价可以单独存在,也可以组合存在。

②活动预热

需要提前配置活动;活动D ; f 9 `还未开始时,用户可以查看活动的相关信息;秒杀y 7 , u活动开始前,对活动进行大力宣传。

③持续时间短

购买的人数数量庞大;商品会迅速售完。在系统流量呈现上,就会出现一个突刺现象,此时的并发访问量是非常高的,大部分秒杀场景下,商品会在极短的时间内售完。

秒杀系统的技术特点

我们可以将秒杀系统的技术特点总结如下:

掌握这些,高并发秒杀系统就不用担心了!

①瞬时并发量非常高

大量用户会在同一时间抢购商品! e ^ o 4 x;瞬间并发峰值非常高。

②读多写少

系统中商品页的访问量p L ( H e R d巨大;商品的可购买数量非常少;库存的查询访问数量远远大于商品的购买数量。

在o V z n U N e 0商品页中往往会加入一些限流措施,例如早期的秒杀系统商+ U q B h品页会加入验证码来平滑前端对系统的访问流量,近期的秒杀系统商品详情页会在用户打开页面时,提示用户登录系统。这都是对系统的访问进行限流的一些措施。

③流程简单

秒杀系统的业务流程一般比较简单;总体上来说,秒杀l W & ~ z e e系统的业务流程可以概括为:下单减库存。

针对这种短时间内大流量的系统来说,就不太适合使用系统扩容了,因为即使系统扩容了,也就是在很短的时间内会使用到扩容后的系统,大部分, X c x e h B ? Z时间内,系统无需扩容即可正常访问。

那么,我们可以采取哪些方案来提升系统的秒杀性能呢?

秒杀系统方案

针对秒杀系统的特点,我们可以采取如下的措施来提升系统的性能。

掌握这些,高并发秒杀系统就不用担心了!

①异步解耦

将整体流程进行拆解,核心流程通过队列方式进行控制。

②限流防刷

控制网站整体流量,提高请求的门槛,避免系统资源耗尽。

③资源控制

将整体流程中的资源调度进行控制,扬长避短。由于应用层能够承载的并发量比缓存的并发量少很多。

所以,在高并发系统中,我们可以直接使用 OpenResty 由负载均衡层访问M Z v ~ + W @ s %缓存,避免了调用应用层的性能损耗。

大家可以到 https://openresty.org/cn/ 来了解有关 OpenResty 更多的知识。

同时,由于秒杀系统中,商品数量比较少,我们也可以使用动态渲染技术,CDN 技术来加速网& ( ? w #站的访问性能。

如果在秒杀活动开始时,并发量太高时,我们可以% , l 0 S将用户的请求放入队列中进行处理,并为用户弹出排队页面。

掌握这些,高并发秒杀系统就不用担心了!

秒杀系统时序图

网上很多的秒杀系统和对秒杀系统的解决方案,并不是真正的秒杀系统,他们采用的只是同步处理请求的方案,一旦并发量真的上来了,他们所谓的秒杀系统的性能会急剧下降。我们先来看一下秒杀系统在同步下单时的时序图。

同步下单流程:

掌握这些,高并发秒杀系统就不用担心了!

①用户发起秒杀请求

在同步下单流程中,首先,用户发起秒杀请求。商城服务需要依次执行如下流程来处理秒杀请求的业务。

识别验证码是g [ ^ e否正确:商城服务判断用户发起秒杀请求时提交的+ U a验证码是否正确。

判断活动是否已经结束:t 0 _ ~ J v y验证当前秒杀活动是否已经结束。

验证访问请求是否处于黑名单:在电商领域中,存在着很多的恶意竞争,也就是说,其他商家可能会通过不正当手段来恶意请求秒杀系统,占用系统大量的带宽和其他系统资源。

此时,就需要使用风控系统等实现x S w E z O v黑名单机制。为了简单,也可以使用拦截器统计访问频次实现黑名单机制。

验证真实库存是否足够:系统需要验证商品的真实库存是否足够,是否能够支持本次秒杀活动的商品库存量。

扣减缓v e h存中的库存:在秒杀业务中,往往会将商品库存等信息存放在缓存中,此p . j & i时,还需要验a c = A证秒杀活动使用的商品库存是否足够,并且需要扣减秒h ^ E杀活动的商品库存数量。

计算秒杀D / # 杀场景中,系统涉及的业务更加复杂的话,会涉及更多的业务操作,这里,我只是列举出一些常见的业务操作y 0 H Y 9。

②提交订单

订单入口:将用户提交的订单信息保存到数据库中。

扣减真实库存:b 9 F p o订单入库后,需要在商品的真实库存中将本次成功下j j G U o u单的商品数量扣除。

如果我们使8 I c用上述流程开发了一个秒杀系统& . ` 7 9 +,当_ 4 * 4 U q B性能不会太高。

之所以你们公司采用同步下单的X F H q _ u方式做秒杀系统没出现大的问题,那是因为你们的U ~ } 6 1 h b秒杀系统的并发量没达到一定的量级,也就是说,你们的秒杀系统的并发量其实并不高。

所以3 ? j [ % S h +,很多所谓的秒杀系统,存在着秒杀的业务,但是称不上真正的秒杀系统,原因1 @ ? 9 R :就在于他们使用的是同步的下单流程,u - d a # u j k限制了系统的并发流量。

之所以上线后没出现太大的问题,是因为系统的并发量不高,不足以压死 C _ = n如下业务流程。

检测验证码是否正确:用户发起秒杀请求时,会将验证码一同发送过来,系统会检验验证码是否有效,并且是否正确。

是否限流:系统会对用户的请求进行是否限流! ^ z d q ,的判断,这里,我们可以通过判断消息队列的长度来进? a ! H P e ,行判断。

因为我们将用户的请求放在了消息队列中,^ & v a c消息队列中堆积的是用户的请求,我们可以根据当前消息队列中存在的待处理的请求数量来判断是否需要对用户的请求进行限流处理。

例如,在秒杀活动中,我们出售 1000 件商品,此时在消息队列中存在 1000 个请求,如果后续仍然有用户发起秒杀请求,u r 7则后续的请求我们可以不再处理,直接向用户返回商品已售完` Q S ^ . *的提示。

掌握这些,高并发秒杀系统就不用担心了!


所以x 9 K p .,使用限流后,我们可以更快的处理用户的请求和释放连接的资源。

发送 MQ:用户的秒杀请求通过前面的验证后,我们就可以将用户的请求参数等信息发送到 MQ 中进行异步处. c O @ y理,同时,向用户响应结果信息。

在商城服务中,会有专门的异步任务处理模块来消费消息队列中的请求,并处理后续的异步流程。

在用户发起秒杀请求时,异步下单流程比同步下单流程处理的业务操作更少,它将后续的操作通过 MQ 发送给异步处理模块进行处理,并迅速向用户返回响应结果,释放请求连接。

②异步处理

我们可以将下单流程的如下操作进行异步处理:

  • 判断活动是否已经E : z 4 8 ) ` y c结束
  • 判断本次请求是否处于系统黑名单,为了防止电商领域同行的恶意竞争可以为系统增加黑d c 9 | A z名单机制,将恶意的请求放入系统的黑名单中。可以使用拦截器统计访问频次来实现} } a H a 5。
  • 扣减缓存中的秒杀商品的库存7 F J l U P V数量。
  • 生成秒杀 Token,这个 Token 是绑定当前3 L H &用户和当前秒杀活动的,只有生成了秒杀 Token 的请求I A @ w q U才有资格进行秒杀活动, p 2 ^ 9 y ^ K。

这里我们引入了异步处理机制,在异步处理中,系统使用多少资o B 5 a s t X W源,分配1 V L m { &多少线程来处理相V Q Q ] ) O r - 5应的任务,是可以进行控制的。

③短轮询查询秒杀结果

这里,可以采取客户端短轮询查询是否获得秒杀资格的方案。例如,客户端可以每隔 3 秒t 2 w }钟轮T 6 # ^ T q询请求服务器,查询是否获得秒杀资格。

这里,我们在服务器的处理就是判断当前用户是否存在秒杀 Token,} ? 1 q J . Y如果服务器为当前用户生成了秒杀 Token,则当前用户存在秒杀资格。

否则继续轮询查询,直到超时或者服务器返回商品已售完或者无秒杀资格等信息为止。

采用短轮询查询秒杀结果时,在页面上我们同样可以提示用户排队处理中,但是此时客户端会每隔几3 u z O秒轮询服务器查询a R y t X秒杀资格的状态,相比于同步下单流程来说,无需长时间占用请求连接。

此时,可能会有网友会问:采用短轮询查询的方式,会不会存在直到超时也查询不到是否具有秒杀资格的状态呢?

答案是:有可能!这里我们试想一下秒杀的真实场景,商家参加秒杀活动本质上不是为了赚E P ; e钱,而是提升商品的销量和商家的知名度,吸引更多的用户来买自己的商品。

所以,我们不必保证用户能够 100% 的查询到是否具有秒杀s h a x # S资格的状态v 9 / v。

④秒杀结算

验D ^ 0 + Q证下单 Token:客户端提交秒杀结算时,会将秒杀 Token 一同提交到服务器,商城服务会验证当. ) ^ p J w前的f B L L | X秒杀 Token 是否有效。

加入秒杀购物车:商城服务在验证秒杀 Token 合法并有效后,会将用户秒杀的商品添加到秒杀t R | :购物车。

⑤提交订单

订单入库:将用户提交的订单信息保存到数据库中。

删除 Token:秒杀商品订单入库成{ ? { + ~ B ? 1 G - q?

这是因为在异步下单流程的设计中,无论是在产品设计上还是在+ h b接口设计上,我们在用户发起秒杀请求阶段对用户的请求进行了限流操作,可以说,系统的限流7 _ r s R操作是非常前置的。

在用户发起秒杀请求时进行了限流,系统的高峰流量已经被平滑解决J Q % 6 ^了,再往后走,其实系统的并发量和系统流量并不是非常高了。

所以,网上很多的文章和帖子中在介绍秒杀系统时,说是在下单时使用异步削峰来进行一些限流操作,那都是在扯淡X v @ 5 *!

因为下单操作在整个秒i ! @ j S ! =杀系统的流程中属于比较靠后的操# R # ) ( X 6作了,限流操作一定要前置处理,在秒杀业务后, F v面的流程中做限流操作是没啥卵用的。

高并发“黑科技”与致胜奇招

假设,在秒杀系统中我们使用 Redis 实现缓存,假设 Redis 的读写并发量在 5 万左右。

我们的商城秒杀业务需要支持的并发量在 100 万左右。如果这 100 万的并发全部打入 Redis 中,Redis 很可能就会挂掉,那么,我们如何解决这个问题呢?

接下来,我们就一起来探讨这个问题。在高并发的秒杀系统中,如果采用 Redis 缓存数据,则 Redis 缓存的并发处理能力是关键,因为很多的前缀操作都需要访问 Redis。

而异步削峰只是基本的操作,关键还是要保证 Redis 的并发处理能力。

解决这个问题的关键思想就9 e i M E O c + j是:分而治之,将商品库存分开放。

暗度陈仓

我们在 Redis 中存储秒杀商品的库存数量时,可以将秒杀商品的库存进行“分割”存储来提升 Redis 的读写并发量。

例如,原来的秒杀商品的 id 为 10001,库存为 1000 件,在 Redis 中的存储为(10001, 1000),我们将原有的库存分割为 5 份,则每份的库存为 200 件。

此时,我们在 Redis 中存储的信息为(1] S = e M D Y 80001_0, 200),(10001_1, L W w, 200),(10001_2, 200),(10001_3, 200),(10001_4, 200)。

掌握这些,高并发秒杀系统就不用担心了!

此时,我们将库存进行分割后,每个分割后的库存使用X S ~ @ _ 2 { 2商品 id 加上一个数字标识来存储。

这样,在对存储商品库存的J f # 1 5每个 Key 进行 Hash 运算时,得出的 Hash 结果是不同的。

这就说明,存储商品库存的 Key 有很大概率不在 Red: C b N 4 b ~is 的同一个槽位中,这就能够& a 提升 Redis 处理请求的性能和并发量。

分割库存后,我们还需要在 Redis 中存储一份商品 id 和分割库存后的 Key 的映射关系,此时映射@ o A Y 8关系的 Key 为商品的 id,也就是 10001。

Value 为分割库存后| * p存储库存信息的 Key,也就是 10001_0,10001_1,10001_2,10001_3,10001_4。在 Redis 中我们可以使用 List 来存储这些值。

在真正处理库存信息时,我们可以先从 Redis 中查询出秒杀商品对i ( j &应的分割库存后的所有 Key,同时使用 AtomicLongG a z 来记录当前的请求数量。

使用请求数量对从 Redis. S J @ 中查询出的秒杀商品对应的分割库存后的所有 Key 的长度进行求模运算,得出的结果为 0,1,2,3,4。

再在前面拼接上商品 id 就可以得出真正的库存缓存的 Key。此时4 | r R,就可以根据这个 Key 直接到* { G Y Redis 中获取相应的库存信息O I l h C。

移花接i M @ y X _ @ w木

在高并发业务场景中,我们可以直接使用 Lua 脚本库(OpenResty)从负载均衡层K # G 0 5 Q直接访问缓存。

这里,我们思考一个场) ! r 5 /景:如果在秒杀2 W H m .业务场景中a ] r v u 1,秒杀的商品被瞬间抢购一空。

此时,用户再发起秒杀请求时, X 1 ; 0 P D ^ f如果系统由负载均衡层请求应用层的各个服务,再由应用层的各个服务访问缓存和数据库。

其实,本质上已经没有任何意义了,因为商品已经卖完了,再通过系统的应用层进行层层校验已经没有太多意义了!!

而应用层的并发访问量是以百为单位的,这又在一定程度上会降低系统的并发度。

为了解决这个问题,此时,我们可以在系统2 ? U的负载均衡层取出用户发送请) Y e | O s s求时携带的用户= 0 1 e i id,商品 id 和秒杀活动 id 等信息,直接通过 Lua 脚本等技术来访问缓存中的库存信息。

如果秒杀商品& = S P I的库存小于或者等于 0,则直接返回用户商品L O y h s已售完的提示信息,而不用再经过应用层的层层校验了。

针对这个架构,我们可以参见本文中的电商系统的架构图(正文开始的第一张图)。

写在最后

最后,附上并发编程需要掌握的核心技能知识图,祝大家在学习并发编程时,少走弯路。

掌握这些,高并发秒杀系统就不用担心了!

后记:记住你比别人强的地方,不是你做过多少年的 CRUD 工作,而是你比别人掌握了更多深入的技能。

不要总停留在 CRUD 的表面工作,理解并掌握底层原理并熟悉源h ; , 9 B o , X [码实现,并形成自己的抽象思维能力,做f @ ` Q到灵活运用,才是你突破瓶颈,脱颖而出的重要方向!

你在刷抖音x ? K G n o 2 Y o,玩游戏的时候,别人都在这里学习,成长,提升,人与人最大的差距其实就是思维。你可能不信,优秀的人,总是在一起。。

作者:冰河技术

来源:冰河技术

小米库存项目不用信丰担心系统秒杀不用担心