秒杀实现技巧

需求分析

“秒杀”这个词在电商行业中出现的频率较高,如京东或者淘宝平台的各种“秒杀”活动,最典型的就是“双11抢购”。

“秒杀”是指在有限的时间内对有限的商品数量进行抢购的一种行为,这是商家以“低价量少”的商品来获取用户的一种营销手段。

01. 功能性需求

其实,整个秒杀的业务场景并不复杂,可即查看参与秒杀的商品信息,加上购买和支付的动作,如下图所示。

a4bd4284023d4a1b8f3fe45e7fe66573.png

 

秒杀业务最大的挑战在于3点:

  • 瞬时:持续时间极短,对于热门且具备极强竞争力的商品通常只有一秒。

  • 流量巨大:因为价格低廉,商品性价比高,而且正常买是需要很高的价格,所以才会吸引大量的用户来争抢。

  • 数量有限:因为商品的低价且性价比高,所以只有很有限的商品数量参与秒杀。

同时,在保证高并发流量承接的前提下,为了增强用户的体验和活动规则的公平性,以及防止遭到恶意破坏等,特此增加如下需求:

(1)用户在秒杀页面无需一直刷新“抢购”按钮,待秒杀活动开始时,按钮自动点亮。

(2)在公平以及防止恶意破坏的原则下,在下单之前增加验证码的录入,或者答题的相关环节。

(3)库存不能出现问题,即不多扣也不少扣。

(4)整个秒杀活动过程持续10分钟。

02. 性能指标预估

通过秒杀的需求描述可得出,当前秒杀活动主要需要预估三块的性能指标:存储容量、并发量、网络带宽。

1)存储容量

由于是秒杀活动,且参与的商品基本都是低价高性价比的,数量是非常有限的。所以,在订单存储上基本不用去过多考虑。

2)并发量

针对5000万用户平均每人访问2次,则并发量为每秒16.7万左右(5000w*2/10*60),在预留一部分,可以预估到每秒25万左右(也可以进行double下)。

3)网络带宽

在带宽方面,需要进行相关优化,采取数据传输越少越好,假设单条传输在0.5KB,则根据并发量预估网络带宽为:977Mb左右(25w*0.5KB=122MB*8bit=977Mb)。

03. 非功能性需求

做任何系统都要考虑非功能性需求,特别是公司的核心系统,当前秒杀业务系统非功能性需求主要体现在如下几点:

  • 高可用,在秒杀活动的整个持续期间内,都能对用户提供服务。

  • 高性能,让每个用户都能感受到极快的秒杀响应,不能出现大批量用户延迟较高的现象。

  • 可扩展,当流量比预期更高时,有平滑扩展的策略(也有部分产品设计成友好的拒绝策略)。

概要设计

通过对秒杀业务的本身认知以及上面提到的秒杀业务需求,本次秒杀系统需要着重设计如下几点:

(1)动静分离:如何保证用户在不刷新页面的情况下,依然能进行秒杀相关数据的获取且不会耽误秒杀活动的开始。

(2)流量分层,针对巨大流量,如何进行有效的防控,以免造成后台服务的不堪重负,以及如何避免前端页面的卡死。

(3)高可用:如何确保后台持续提供服务。

(4)扣减库存:如何有效扣减库存。

 

01. 动静分离

动静分离是指,将静态页面与动态页面(或者静态数据与动态数据)解耦分离,用不同系统承载对应流量。这样可以提升整个服务访问性能和可维护性。

商品秒杀页面的静态数据以及动态数据,均是不同的地方提供,如下图所示。

3817608c4d644588866fc07f6b9bbf9d.png

 

静态数据是指,页面中几乎不怎么变化的数据(即不依据用户的Cookie、基本信息、地域,及时间等各种属性来生成的数据),例如:

  • CSS和JavaScript中的静态文件。

  • 活动页中的HTML静态文件。

  • 图片等相关资源文件。

  • 其他与用户信息无关的静态数据。

对于这种分离出来的静态数据可以进行缓存。在缓存之后,这些静态数据的访问效率就提高了,系统也更快了。可以使用代理服务器进行静态数据的缓存。

动态数据是指,依据当前用户属性动态生成的数据,在浏览淘宝首页时,每个用户所看到的商品都是不一样的,这就是淘宝的“千人千面”——针对不同用户做不同的推荐;在百度搜索中是依据不同用户的输入条件,以及用户的习惯给出不同的结果页。这其中的数据就是动态数据。

 

02. 流量分层

在“秒杀”业务中,商品价格具有强大的吸引力,所以会受到很多用户的关注,但是商品数量是有限的。所以,在千万的用户中可能只有100人能得到商品,对于系统来说,有90%以上的流量属于无效流量。

“秒杀”业务希望有大量的用户来关注“秒杀”活动,但是在用户真正下单时又不能将这些流量全部放过,所以,需要设计一套高效的流量管控方案,来有效地控制请求流量,过滤掉没必要的流量。

对于瞬时流量洪峰可以采用倒三角的分层级逐层控制方式,共分为CDN、反向代理(Nginx)、后端服务及DB这四个层级。接下来,就来看看每一层级是怎么控制流量的,如下图所示。

5c160b2842ce4f58b1ec6e0b946a8162.png

 

03. 高可用

要想在整个“秒杀”活动持续期间内,依然能对用户提供良好的体验,则秒杀系统架构在设计时不能设计成单节点的架构。

单节点是所有系统设计中的大忌,因为单节点系统意味着系统的不稳定性较高,可能会出现不可用的情况,会给企业带来直接的损失。在系统设计(特别是“秒杀”这类对高并发要求极高的系统)时,必须保证系统的高可用,如下图所示。

cecd952a713249e5a28c363b46e0e64d.png

 

04. 扣减库存

对于“秒杀”活动,通常,公司是不允许商品超卖(即下单成功的数量不能大于商品存存数量)的。一旦超卖,则会给公司造成损失。如果被恶意流量利用,则损失是巨大的。

库存对于电商平台来说是一个重要的业务指标,所以在技术上需要合理设计扣减库存,不能出现“超卖”现象。通常,扣减库存常有以下3种方式:

下单扣库存:在用户下单后就扣减库存。

支付扣库存:用户付完款后再扣减库存。

预扣库存:在用户下完订单后,系统会为其锁定库存一段时间,在超过锁定时间后会自动释放锁定的库存。

05. 系统架构设计

根据上面讨论,针对当前秒杀架构如下图所示。09134a35d95143ae9aa3acd72f3f0a27.png

 

如上架构比较简洁,主要分为以下5层。

  • 用户层:用户端的展现部分,主要涉及商品的相关信息及当前“秒杀”活动的信息。

  • CDN层:缓存“秒杀”活动的静态资源文件。

  • 负载均衡层:拦截请求及分发路由等。

  • 服务层:“秒杀”活动的具体交易的相关逻辑处理。

  • 基础设施层:数据存储、大数据计算及消息推送相关操作。

其部署架构图如下:

4b5d1464133c41c4bc1f3e96dba32ce9.png

 

详细设计

01. 动静分离设计

实施动静分离架构可以采用“分而治之”的办法,即将动态数据和静态数据解耦,分别使用各自的架构系统来承载对应的流量:

  • 对于静态数据,推荐缩短用户请求路径,因为路径越短,访问速度也就越快。另外,即尽可能将静态数据缓存起来。

  • 对于动态数据,一般用户端需要和服务端进行交互才能获取,所以,请求路径较长,访问速度会慢一点。下图展示了动静分离方案。

静态数据访问速度很快,而动态数据访问速度较慢。那么试想下,可以将需要动态获取的数据给提前生成好,然后使用静态页面加速技术来访问吗?如果这样可以,那动态数据访问的速度就变快了。

这样是可以的,需要用到比较流流行的“页面静态化”技术。页面静态化技术是指,直接缓存HTTP连接,而不仅是缓存数据。如下图所示,代理服务器根据请求的URL直接将HTTP对应的响应头及响应消息体返回,流程简洁且高效。

a187e0129d884f709c5e150d8d53a6da.png

 

02. 流量分层设计

流量分层主要体现在对于CDN层、反向代理层、后端服务层以及数据层流量进行控制。

1)CDN层流量控制

由动静分离技术可以想到:应尽量将尽可能多的数据提前生成,然后将其放入CDN节点缓存中(因为CDN层在物理架构上离用户比较近)。

所以,如果绝大部分的流量都在这一层获取数据,则到达后端的流量会减少很多,如下图所示。

 

 

java实现秒杀系统@Controller @RequestMapping("seckill")//url:/模块/资源/{id}/细分 /seckill/list public class SeckillController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method = RequestMethod.GET) public String list(Model model){ //获取列表页 List list=seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp+model = ModelAndView return "list";//WEB-INF/jsp/"list".jsp } @RequestMapping(value = "/{seckillId}/detail",method = RequestMethod.GET) public String detail(@PathVariable("seckillId") Long seckillId, Model model){ if (seckillId == null){ return "redirect:/seckill/list"; } Seckill seckill = seckillService.getById(seckillId); if (seckill == null){ return "forward:/seckill/list"; } model.addAttribute("seckill",seckill); return "detail"; } //ajax json @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) @ResponseBody public SeckillResult exposer(@PathVariable("seckillId") Long seckillId){ SeckillResult result; try { Exposer exposer =seckillService.exportSeckillUrl(seckillId); result = new SeckillResult(true,exposer); } catch (Exception e) { logger.error(e.getMessage(),e); result = new SeckillResult(false,e.getMessage()); } return result; } @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"} ) @ResponseBody public SeckillResult execute(@PathVariable("seckillId")Long seckillId,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值