电商项目围绕运行展开的秒杀是如何实现的
目前针对秒杀的解决方案,大多是分库分表、缓存、消息队列等技术实现,但凡能想到的技术都会写上这么一段操作
但是个人觉得应对秒杀这样处在流量峰值的业务,需要仔细分析这个业务的特性,以及需要判断自身业务的优点,根据自己系统的业务量来确定采用哪些技术亮点
举个例子:日活10万的系统,采用了分库分表、缓存、消息队列、限流降级等等技术手段,在功能上基本能达到预期,但是资源或多或少会有些浪费,也可能这些技术中只采用一个限流手段就足够,因此还是要根据系统自身去考察选用那些技术手段,比如分库分表这样的操作实际上是属于大手笔,需要投入的金钱是不小的
言归正传,分析一下秒杀业务,其实不难发现场景特点:
1、短期的流量峰值状态,即在某个时间段会有大量的其你去涌入,该时间段大部分已知
2、请求的数据带会比较集中,具有热点性,就是大量请求统一数据
3、请求的成功率反而较低,大量的请求中可能只有少量会成功处理完业务逻辑并提交正确数据
4、请求的流量峰值通常是发生在下单操作之前,在付款阶段其实流量峰值不存在
分析一下通常有很多方式可以处理:
一、静态资源预加载
静态资源通常指html里面的图片、视音频,都是在页面上不会变动的资源,如果想最快让用户获取, 通常是放在离用户端较近的位置。比如:浏览器预加载的本地缓存,缓存过期的时候,优先是推荐从CDN中去获取,CDN方式是应对静态资源访问出现的流量峰值最简单粗暴的方法,也是最有效的解决方案。如果没有CDN的话,建议把静态资源的服务器和后端业务分离,避免因为静态资源加载影响正常业务
二、业务层面让步
业务和技术同时面对一个秒杀活动的时候,对该业务负责的产品经理不会设计出这样的秒杀: 用户点击秒杀马上确定是否下单成功,做分布式的大家应该都想保证数据一致性,数据正常刷新到数据库,这样在可用性上就有很大牺牲。其实这里一点即 秒杀系统的可用性要比数据的一致性优先级更高,通常会选用最终一致性来完成秒杀,即在用户看来,点击秒杀按钮后,进入一个等待的提示,这个提示就是技术实现的 异步处理,异步处理的时候页面上就是一个等待的过程,这也就是业务和技术上的一个权衡,在秒杀进行时,出现验证码或者网络加载等情况,这都是技术和业务之间的让步
第一招:限流降级
出现短时间流量峰值,我们做最简单的限流,被限制的请求可以直接返回,客户端直接显示请求中,即让限制数量内的请求进入逻辑处理,当10000个请求削减成100个请求的时候,系统稍微优化即能顶住,这里限流的策略也就有很多方案了,比如:
1、限制一个用户请求次数,每个用户10s只允许请求一次
2、限制ip请求次数,每个ip10s只允许请求一次
第二招:消息队列
消息队列相当于一个快速的数据容器,作为一个缓冲层来应对短时间流量峰值。使用场景来看,是中间层级速率设备的一个权衡,当然很明显是一个异步流程。
在秒杀系统中,大量的请求会先进入消息队列,直接削平了流量的峰值,把流量均匀放入到数据容器中,把秒杀下单的流程异步化,只要你把请求都存入队列,消费端慢慢的消费,大家正常稳定运行即可。这个地方要注意一点的是,出入队列的速度不一样,消费的速度是比投递的速度慢的,因此性能方面可能会有所降低
消息队列的最大作用在于系统解耦,能把用户下单和用户支付解耦,当系统承载量扩大,可以对不同应用功能单独扩容
第三招:缓存
在秒杀系统的时候,大量用户在下单或者访问数据的时候,有大量用户下单写数据库的这个操作,还有更大量的用户请求下单结果这个读数据库的操作。用户点击秒杀后,系统会弹出提示框,大多系统是轮询用户的下单结果,这里的缓存提供的最大最庸就是提供读操作的快速响应
秒杀系统可以选择这样做:
1、用户点击下单按钮,请求经过限流组件,如果成功则进入下单环节(这里可以让请求进入消息队列, 进行消费,异步下单)
2、服务端采用的缓存方式,可以是redis缓存也可以是其他缓存组件,都是用来存放下单成功的用户信息(和订单信息)
3、客户端不间断轮询,去查询缓存,查询到的信息确定为下单成功,再进入下一步支付环节,查询不到的订单说明没成功,及时给用户返回下单失败的响应
4、服务端显示该用户下单成功后,往缓存中写入数据,该用户下次再次查询的时候会提示下单成功
以上几点就是要让用户在整个流程中用户信息订单信息都能够通畅的进行存储和查询,不会出现异常情况
注意的几点有:缓存的过期时间设置,用户下单暂未成功的状态显示,缓存数据和数据库数据的一致性(这里可以考虑主从库同步,主读从写),用户在下单的时候其实读取的数据还包括商品信息,在短时间流量峰值的时候也可以以缓存副本的形式提供给用户,提高系统的吞吐量
综上 限流+ 消息队列是常见的做法,分库分表是大手笔,还需要审查自身体系统后才进行,缓存也是根据数据体量来实施,秒杀系统这一方面的理解就是以上内容了。