30.【学习心得】学习心得-秒杀架构

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 【学习心得】学习心得-秒杀架构

文档参考:书名:《从程序员到架构师:大数据量、缓存、高并发、微服务、多团队协同等核心场景实战》-王伟杰

image.png

前文如下:


23.【学习心得】学习心得-冷热分离概述

24.【学习心得】学习心得-如何分离冷热数据

25.【学习心得】学习心得-基于MySQL的分表分库

26.【学习心得】学习心得-读缓存

27.【学习心得】学习心得-如何更新redis缓存

28.【学习心得】学习心得-写缓存

29.【学习心得】学习心得-写缓存实现思路


1. 业务场景:设计秒杀架构必知必会的那些事


某一次公司策划了一场秒杀活动,该活动提供了100件特价商品(商品价格非常低),供用户于当年10月10日22点10分0秒开始秒杀。


当时平台已经积累了几千万的用户量,预计数十万的用户对这些特价商品感兴趣。根据经验,特价商品一般会在1~2秒内被一抢而光,剩余时间涌进来的流量用户只能看到秒杀结束界面,因此预测秒杀开启那一瞬间会出现一个流量峰值。


这也是一场临时性的活动,领导要求别加太多服务器,也别花太多时间重构架构,也就是说需要以最小的技术代价来应对这次秒杀活动。


因此,这次秒杀架构的设计目标是以较小的改动来保证秒杀时的流量洪流不会冲垮服务器。对于秒杀架构设计而言,其难点在于僧多粥少,因此设计秒杀架构时,一般需要遵循商品不能超卖、下单成功的订单数据不能丢失、服务器和数据库不能崩溃、尽量别让机器人抢走商品这4个原则。


2. 整体思路


其实秒杀架构的设计方案就是一个不断过滤请求的过程。从系统架构层面来说,秒杀系统的分层设计思路如图所示。


网络异常,图片无法展示
|


在图中发现,秒杀系统的架构设计目标是尽量在上层处理用户请求,不让其往下层游动。那具体如何实现呢?由于整个秒杀系统涉及多个用户操作步骤,所以解决如何将请求拦截在系统上游这个问题时,需要结合实际业务流程,将用户的每个操作步骤考虑在内。这里通过一张图来描述秒杀系统的具体业务流程,如下图所示。


网络异常,图片无法展示
|


接下来就按照秒杀系统的业务流程,来一步步讲解如何将请求拦截在系统上游。


2.1 浏览页面如何将请求拦截在上游


在以往的秒杀系统架构经历中,曾出现过这么一种状况:当时把系统的方方面面都考虑到了,但是活动一上线,第三方监控系统就显示异常,检查后发现所有服务器的性能指标都没问题,唯独出口带宽有问题,它被占满了。


结果就是用户参与活动时页面出现严重卡顿,用户抱怨不断。


一朝被蛇咬,十年怕井绳。有了这次惨痛经历,带宽这件事情就被牢牢记在脑子里,所以在之后的项目中,静态资源尽量使用CDN(内容分发网络),如果涉及PC网站,还必须首先进行前后端分离。

说到这里,先简单介绍一下什么是CDN。比如,请求访问的地址是static.weimu.xx/1.jpg,这个地址指向自己的服务器,经过改造后,static.weimu.xx这个域名的解析就会交给CDN服务商。

CDN服务商在全国各地都有服务器,服务器中存放着静态资源的缓存。CDN收到这个域名后,首先会寻找一台响应最快的服务器,并指向这个服务器的IP。 如果对细节感兴趣,可以查阅其他资料。因此,使用CDN的好处是不用花费自己的服务器资源和带宽,且响应速度快。通过这种方式,可以把静态资源的压力拦截在系统分层的外面。


那如果是动态的请求该怎么办?有以下3种实现方式。


1)评论、商品详情、购买数量等相关的请求,一般都是通过JS(JavaScript)在后台动态调用。在这个场景中,可以把动态的数据与页面进行整合,比如把每个秒杀商品的详情页面变成静态页面,然后再放入CDN。如果觉得改造太大,也可以把它放在Redis缓存中,不过笔者更倾向于CDN。

2)判断服务器时间并设置开启秒杀的标识。一般页面中都有JS,它通过访问服务器获取服务器时间,然后根据时间开启秒杀下单的按钮,即判断秒杀开始时,会将下单按钮设置为可用。针对获取服务器时间的这个请求,把它放在静态资源或负载均衡那层即可,这样用户请求就不会进入系统下游。

3)判断秒杀结束。具体做法是将秒杀结束的标识放在Cookie中,如果Cookie中没有结束标识,请求就会进入后台服务器,后台服务器判断本地内存没有结束标识,就会进入缓存,如果缓存中也没有结束标识,那就说明秒杀没有结束。

总体来说,对于浏览页面的用户行为,需要把用户请求尽量拦截在CDN、静态资源或负载均衡侧,如果确实做不到,也要拦截在缓存中。


2.2 下单页面如何将请求拦截在上游

1.进入下单页面为了防止别人通过爬虫抓取下单页面信息,从而给服务器增加压力,需要在下单页面做以下两层防护,从而防止恶意请求重复提交。


1)页面URL后台动态获取:按照正常的活动设计流程,用户只有在秒杀活动开启后才可进入下单页面,但难免有人在活动开启前直接获取其URL并不断刷新,这样恶意请求就到了后台服务器。虽然后台服务器也可以拦截恶意请求,但是这会给它徒增不少压力。此时主要使用一个特别的URL进行处理(不把它放在静态页面中,而是通过后台动态获取)。前面介绍了JS可以用来判断秒杀开始时间,秒杀时间一到,它便可以通过另一个请求获取这个URL。

2)用户点击下单页面的购买按钮后,将此按钮设为Disable(不可用),防止用户不断点击它。


2.提交订单


秒杀系统架构方案的核心是订单提交,因为这个步骤的逻辑最复杂,而其他步骤仅涉及页面展示的逻辑,针对高并发问题使用缓存或者CDN进行处理难度不大。因此,在订单提交环节,要想尽一切办法在系统各个分层中把一些不必要的请求过滤掉。


(1)网关层面过滤请求对系统而言,如果可以在网关层面拦截用户请求,那么这个方案的性价比就很高。要是能在这一层过滤95%以上的请求,整个系统也将很稳定。那在网关层面如何实现请求过滤呢?可以做3种限制。


1)限定每个用户的访问频率,比如每5秒下单一次。

2)限定每个IP的访问频率。这种方式是为了避免有人通过机器人自动下单,导致错杀真实用户。

3)把一个时间段内的请求拦截掉一定比例,或者只允许特定数量的请求进入后台服务器。这里可以使用限流的漏桶或令牌桶算法,第12章将详细展开。前两种限制比较简单,在nginx上就能快速完成配置,第3种限流方式也不复杂,相关的原理在后面的章节会讲。


(2)后台服务器过滤请求

请求进入后台服务器后,目标已经不是如何过滤请求了,而是如何保证特价商品不超卖,以及如何保证特价商品订单数据的准确性。


具体如何实现呢?主要考虑以下4点。

1)商品库存放入缓存Redis中:如果每个请求都前往数据库查询商品库存,数据库将无法承受,因此需要把商品库存放在缓存中,这样每次用户下单前,就先使用decr操作扣减库存,判断返回值。如果Redis的库存扣减后小于0,说明秒杀失败,将库存用incr操作恢复;如果Redis的库存扣减后不小于0,说明秒杀成功,开始创建订单。把库存放入Redis时,下单的逻辑都是基于缓存的库存为第一现场。但是如果这时候有别的服务或者代码修改了数据库里面的库存,怎么办?这时的做法就是确保在秒杀期间不做上架或修改库存之类的业务操作,即不通过技术,而是通过业务流程来保证。

2)订单写入缓存中:在第5章介绍写缓存时提过一个方案,即订单数据先不放入数据库,而是放到缓存中,然后每隔一段时间(比如100毫秒)批量插入一批订单。用户下单后,首先进入一个等待页面,然后这个页面向后台定时轮询订单数据。轮询过程中,后台先在Redis中查询订单数据,查不到就说明数据已经落库,再去数据库查询订单数据,查到后直接返回给用户,用户收到消息通知后可以直接进入付款页面支付;在数据库查询订单数据时,查不到说明秒杀失败(理论上不会查不到,如果一直查不到就需要抛出异常并跟踪处理)。

3)订单批量落库:需要定期将订单批量落库,且在订单落库时扣减数据库中的库存。这个做法和第6章中的写缓存一样,这里不再重复。

4)Redis停止工作(挂掉)怎么办:虽然讲了这么多关于后台服务器的逻辑,在秒杀架构里面,最重要的反而是网关层的限流,它挡住了大部分的流量,进入后台服务器的流量并不多。不过仍然要考虑


针对Redis停止工作的情况,分别处理前面的3种状况。


比如读Redis中的库存时,如果失败了,那就让它直接去数据库扣减库存,把那些incr和decr的逻辑放到数据库去;若是把订单写入缓存的时候失败了,那就直接将订单数据写入数据库中,然后就不需要处理后面批量落库的逻辑了。以上就是订单提交操作的架构设计,不难看出它主要是在网关层和后台服务器进行相关设计。


2.3 付款页面如何将请求拦截在上游


在付款页面不需要再过滤用户请求了。在这个环节,除了保障数据的一致性外,还有一个要点:如果业务逻辑中出现了一个订单未及时付款而被取消的情况,记得把数据库及Redis的库存加回去。


2.4 整体服务器架构


再来回顾一下秒杀系统的分层思路,这也是秒杀系统的整体服务器架构方案,如图所示。


网络异常,图片无法展示
|


为了保障秒杀系统的高可用性,在整体服务器架构中,需要保证图7-3中所有的层级都是高可用的。因此,静态资源服务器、网关、后台服务器均需要配置负载均衡,而缓存Redis和数据库均需要配置集群模式。


整体服务器架构中还有一个重要组成部分——MQ,因为这次的秒杀架构方案中不涉及它的设计逻辑,所以并未在上面的分层中提及它。不过,服务间触发通知时,就需要使用它了,因此也需要保证它是高可用的(这里要把主从、分片、Failover机制都考虑进去)

3 小结


到这里,秒杀架构的注意事项就讲完了。因为很多注意事项在前面几个场景一一介绍过,所以这一章讲解的内容就比较简练。表7-1中整理了一份秒杀系统设计Checklist,供大家参考。


网络异常,图片无法展示
|


这个场景中还有以下3个要点需要注意。

1)假设后台某服务因秒杀崩溃了,如何避免其他服务雪崩?这一点会在第10章详细展开。

2)网关层的限流。

3)付款的数据一致性。



相关文章
|
2天前
|
存储 关系型数据库 数据库
个人学习ack-eci架构
针对无状态应用进行容器化改造,同时有应对高峰业务以及定时、批量计算任务对容器集群节点计算资源有高弹性低成本优化的需求的用户,利用云上资源的灵活性和规模化优势,构建云上高弹性、稳定、成本优化的服务。
38 0
|
7月前
|
设计模式 架构师 Java
阿里P8架构师都要学习研究的java加强版23种设计模式神级PDF文档
说在前面的话 Java作为老牌纯正的编程语言,在规范性上有着天然优势。因此本版的设计模式讲解全部用Java语言来描述,并针对Java语言的特性对讲解内容做了相当大的改动。 不知道大家是否听过编程界的一段话:掌握设计模式相当于华山派的"气宗",是程序员的内功修为,虽然在同样的学习时间下,类似Python这种"剑宗"的开发模式见效更快,但是长远来看,"气宗"才是走向软件架构师以上级别的必由之路。 所以,掌握气宗就掌握了编程命脉,然而学习设计模式有四大境界: 接下来给大家分享的就是java溢彩加强版大话设计模式包含的内容知识点。 总目录 主要内容 本文是百万销量的经典畅销书《
131 0
|
2天前
|
存储 弹性计算 安全
云计算——ACA学习 云计算架构
云计算——ACA学习 云计算架构
202 0
|
2天前
|
弹性计算 数据库 Docker
学习阿里云架构设计知识2-wp搭建及配置
VPC分区清晰架构,VSW网络分隔,CEN连通VPC,按量付费小规格,均衡策略,ESS/ACK内置SNAT,ECS用NAT上网。建DMZ需VPC、VSW、NAT、EIP。主系统多VPC/VSW配ECS和Redis,CEN全连接。CEN设路由表,外网访问设DMZ、CEN、EIP,加堡垒机。Web系统ACR部署WordPress,配数据库。验证WordPress、弹性伸缩,测外访、发文、负载。含架构图。
28 1
学习阿里云架构设计知识2-wp搭建及配置
|
2天前
|
SpringCloudAlibaba Dubbo 应用服务中间件
【微服务】微服务初步认识 - 微服务技术如何学习 · 认识微服务架构
【微服务】微服务初步认识 - 微服务技术如何学习 · 认识微服务架构
12 0
|
2天前
|
Kubernetes API 调度
Kubernetes学习-核心概念篇(二) 集群架构与组件
Kubernetes学习-核心概念篇(二) 集群架构与组件
|
2天前
|
架构师 算法 Java
阿里年薪百万的P7架构师简历都长什么样?他们都是怎么学习的?
我有一个朋友最近想从一个中型企业跳槽到大厂,目标瞄准了美团、滴滴、字节跳动等大厂,但投了简历,都石沉大海了!
|
2天前
|
负载均衡 应用服务中间件 Linux
深入浅出学习透析Nginx服务器的架构分析及原理分析「底层技术原理+运作架构机制」
深入浅出学习透析Nginx服务器的架构分析及原理分析「底层技术原理+运作架构机制」
44 0
|
2天前
|
消息中间件 缓存 Java
SpringBoot的架构学习之路
SpringBoot的架构学习之路