目录
秒杀系统架构设计都有哪些关键点?
设计秒杀系统时应该注意的5个架构原则
如何才能做好动静分离?有哪些方案可选?
二八原则:有针对性地处理好系统的“热点数据”
流量削峰这事应该怎么做?
影响性能的因素有哪些?又该如何提高系统的性能?
秒杀系统“减库存”设计的核心逻辑
准备Plan B:如何设计兜底方案?
稳(高可用):虽然我介绍了很多极致的优化思路,但现实中总难免出现一些我们考虑不到的情况,所以要保证系统的高可用和正确性,我们还要设计一个 PlanB 来兜底,以便在最坏情况 发生时仍然能够从容应对。专栏的最后,我将带你思考可以从哪些环节来设计兜底方案。
准(一致性):秒杀中商品减库存的实现方式同样关键。可想而知,有限数量的商品在同一时刻被 很多倍的请求同时来减库存,减库存又分为“拍下减库存”“付款减库存”以及预扣等几 种,在大并发更新的过程中都要保证数据的准确性,其难度可想而知。因此,我将用一篇文章来专门讲解如何设计秒杀减库存方案。
快(高性能):秒杀涉及大量的并发读和并发写,因此支持高并发访问这点非常关键。本专栏将从设计数据的动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化这 4 个方面重点介绍。
“4 要 1 不要”
一个是指用户请求的数据能少就少。1)数据传输需要时间。2)数据需要服务器做处理,消耗CPU。例如,简化秒杀页面,去掉不必要的装饰效果
一个是系统依赖的数据能少就少。1)包括系统完成某些业务逻辑需要读取和保存的数据,和数据库打交道。2)调用其他服务会涉及数据的序列化和反序列化,消耗CPU
用户请求返回后浏览器进行渲染还包括额外的请求。解决:请求合并,响应文件合并返回
所谓的“路径”,就是用户发出请求到返回数据的这个过程,需要经过的中间节点的数量。节点可以表示为一个新的socket连接,每增加一个连接都会增加新的不确定性。
解决:将相互强依赖的应用合并部署在一起,把远程调用变成JVM内部之间的方法调用。
所谓依赖,指的是完成一次用户请求必须依赖的系统或服务,这里的依赖指得是强依赖。
对系统进行分级,0级系统,1级系统。。。0级系统是重要的系统的话,那么0级系统依赖的就是强依赖系统。
在极端的情况下可以将系统降级。比如支付系统是0级系统,优惠券系统是1级系统。可以将优惠券降级,防止支付系统被优惠券系统拖垮。
单点意味着没有备份,风险不可控。解决:避免服务的状态和机器绑定,把服务无状态化,这样服务器可以在机器中随意移动。
秒杀系统架构
秒杀系统快:提高单次请求的效率;减少没必要的请求
“动态数据”和“静态数据”的主要区别就是看页面中输出的数据是否和 URL、浏 览者、时间、地域相关,以及是否含有 Cookie 等私密数据。也就是所谓“动态”还是“静态”,并不是说数据本身是否动静,而是数据中是否含有和访问者相关的个性化数据。
可以对分离出来的静态数据做缓存,有了缓存之后,静态数据的“访问 效率”自然就提高了。
如何对静态数据做缓存
热点操作:例如大量的刷新操作,大量的添加购物车
热点数据:用户的热点请求对应的数据
静态热点数据:能够提前预测的热点数据。使用卖家报名提前统计,大数据分析。实时性较差
动态热点数据:系统在运行过程中临时产生的热点
处理热点数据
处理热点数据通常有几种思路:一是优化,二是限制,三是隔离。
优化
缓存热点数据,如果进行了动静分离,可以长期缓存静态数据。缓存热点数据更多的是”临时“缓存,都用一个队列短暂地缓存数秒钟,由于队列长度有限,可以使用LRU淘汰算法替换。
限制
限制:一种保护机制。例如对被访问商品地ID做一致性Hash,然后根据Hash做粪桶,每个分桶设置一个处理队列。防止某些热点商品占用太多地服务器资源。
隔离
将热点数据隔离出来,不让1%地数据影响到另外地99%,同时也可以针对这1%的数据做优化。业务隔离、系统隔离、数据隔离
对照“4 要 1 不要”原则,它可以减少请求量,也可以减少请求的路径。
削峰的存在,一是可 以让服务端处理变得更加平稳,二是可以节省服务器的资源成本。
针对秒杀这一场景,削峰从本 质上来说就是更多地延缓用户请求的发出,以便减少和过滤掉一些无效请求,它遵从“请求数要 尽量少”的原则。
流量削峰的一些操作思路:排队、答题、分层过滤。
排队
是用消息队列来缓冲瞬时流量。中间通过一个队列在一端承接瞬时的流量洪峰,在另一端平滑地将消息推送出去
答题
为了增加购买的复杂度,有两个目的。
一是防止部分买家使用秒杀器在参加秒杀时作弊。
二是延缓请求,起到对请求流量销峰的作用
分层过滤
分层过滤的核心思想是:在不同的层次尽可能地过滤掉无效请求,让“漏斗”最末端的才是有效 请求。而要达到这种效果,我们就必须对数据做分层的校验。
分层校验的基本原则:
分层校验的目的是:在读系统中,尽量减少由于一致性校验带来的系统瓶颈,但是尽量将不影响性能的检查条件提前,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求、营销等价物是否充足等;在写数据系统中,主要对写的数据 (如“库存”)做一致性检查,最后在数据库层保证数据的最终准确性(如“库存”不能减为负数)。
削峰的 3 种处理方式:一个是通过队列来缓冲请求,即控制请求的发出;一个是通过答题来延长请求发出的时间,在请求发出后承接请求时进行控制,最后再对不符合条件的请求进行过滤;最后一种是对请求进行分层过滤。
第二篇和第三篇从动静分离和热点数据两个维度,介绍了如何有针对性地对数据进行区分和优化处理;第四篇介绍了在保证实现基本业务功能的前提下,尽量减少和过滤一些无效请求的思路。
影响性能的因素
要提升性能就要减少CPU的执行时间,另外就是要设置一个合理的并发线程数。
如何发现瓶颈
就服务器而言,会出现瓶颈的地方有很多,例如CPU、内存、磁盘以及网络等都可能会导致瓶颈。此外,不同的系统对瓶颈的关注度也不一样,例如对缓存系统而言,制约它的是内存,而对 存储型系统来说 I/O 更容易是瓶颈。
对于秒杀场景而言,它的瓶颈更多的发生在CPU
如果海量请求涌过来,你的页面又比较大,那么网络就有可能出现瓶颈。
如何优化系统
对于Java系统来说,可以优化的地方有很多:比如:减少编码、减少序列化、Java极致优化、并发读优化。
性能优化要从发现短板开始。
下单减库存
下单时直接通过数据库的事务机制控制商品库存。可能恶意下单,下单所有的商品但是不付款。
下单减库存数据一致性:事务判断,保证减库存后库存不能为负数,否则就进行回滚。将库存字段设置为无符号整形,小于0后SQL语句就会报错。
付款减库存
买家付款才减库存,可能出现买家下单后付不了款的情况。
预扣库存
买家下单后,库存为其保留一段时间(如10分钟),超过这个时间库存自动释放。买家付款时检验订单是都超时,尝试扣款成功后实际的减库存。下单预减库存,付款实际减库存。有人恶意下单,10分钟后再恶意下单。结合防作弊措施,给经常下单不付款的人表示,给某些商品设置最大购买件数。
降级
所谓“降级”,就是当系统的容量达到一定程度时,限制或者关闭系统的某些非核心功能,从而 把有限的资源保留给更核心的业务。例如,将成交记录的获取从展示20条降级只展示5条
限流
限流就是当系统容量达到瓶颈时,我们需要通过限制一部分流量来保护系统,并做到既可以 人工执行开关,也支持自动化保护的措施。
拒绝服务
如果限流还不能解决问题,最后一招就是直接拒绝服务了。