爱收集资源网

秒杀系统设计:高可用与正确性

网络整理 2023-09-17 00:04

参考来源:极客时间《如何设计一个秒杀系统》1.概述

秒杀系统碰到的问题及解决方式:

并发读:尽量降低用户到服务端来“读”数据,或则让她们读更少的数据

并发写:在数据库层面独立下来一个库,做特殊的处理。设计兜底方案,以避免最坏的情况发生

秒杀系统整体构架目标:

稳:高可用,保证秒杀活动顺利完成。流量符合预期时肯定要稳定,超出预期时也同样不能掉项链。

准:保证数据的一致性。例:秒杀10台iPhone,那就只能成交10台,多一台少一台都不行。

快:高性能。不光是服务端要做极至的性能优化,并且在整个恳求链路上都要做协同的优化。

秒杀系统整体构架设计概述:

高可用:要保证系统的高可用和正确性,还要设计一个PlanB来兜底,便于在最坏情况发生时依然就能从容应对。

一致性:怎么设计秒杀减库存方案?减库存又分为“拍下减库存”“付款减库存”以及“预扣”等几种,在大并发更新的过程中要保证数据的确切性。

高性能:数据的动静分离方案、热点的发觉与隔离、请求的削峰与分层过滤、服务端的极至优化。

秒杀系统设计5大原则:

1.数据要尽量少

指用户恳求的数据能少就少。恳求的数据包括上传给系统的数据和系统返回给用户的数据。

为何“数据要尽量少”呢?

首先,这种数据在网路上传输须要时间,不管是恳求数据还是返回数据都须要服务器做处理,而服务器在写网路时一般都要做压缩和字符编码,这种都十分消耗CPU。所以降低传输的数据量可以明显降低CPU的使用。比如,我们可以简化秒杀页面的大小,除去何必要的页面家装疗效,等等。

其次,要求系统依赖的数据能少就少,调用其他服务会涉及数据的序列化和反序列化,而这也是CPU的一大杀手,同样也会降低延时。数据库本身也容易成为一个困局,所以和数据库打交道越少越好,数据越简单、越小则越好。

2.恳求数要尽量少

用户恳求的页面返回后,浏览器渲染这个页面还要包含其他的额外恳求,譬如说,这个页面依赖的CSS/JavaScript、图片,以及Ajax恳求等等都定义为“额外恳求”,这种额外恳求应当尽量少。由于浏览器每发出一个恳求都多少会有一些消耗,比如构建联接要做三次握手,有的时侯有页面依赖或则联接数限制,一些恳求(比如JavaScript)还须要串行加载等。另外,若果不同恳求的域名不一样的话,还涉及那些域名的DNS解析,可能会历时更久。所以你要记住的是,降低恳求数可以明显降低以上这种诱因引起的资源消耗。

比如,降低恳求数最常用的一个实践就是合并CSS和JavaScript文件,把多个JavaScript文件合并成一个文件,在URL中用冒号隔开(,module-jhs/index.xtpl.js,module-focus/index.xtpl.js)。这些方法在服务端一直是单个文件各自储存,只是服务端会有一个组件解析这个URL,之后动态把这种文件合并上去一起返回。

3.路径要尽量短

所谓“路径”,就是用户发出恳求到返回数据这个过程中,需求经过的中间的节点数。

这种节点可以表示为一个系统或则一个新的Socket联接(例如代理服务器只是创建一个新的Socket联接来转发恳求)。每经过一个节点,通常还会形成一个新的Socket联接。每降低一个联接就会降低新的不确定性。减短恳求路径除了可以降低可用性,同样可以有效提高性能(降低中间节点可以降低数据的序列化与反序列化),并降低延时(可以降低网路传输历时)。

方式:多个互相强依赖的应用合并布署在一起,把远程过程调用(RPC)弄成JVM内部之间的方式调用。

4.依赖要尽量少

所谓依赖,指的是要完成一次用户恳求必须依赖的系统或则服务,这儿的依赖指的是强依赖。

例:例如说你要展示秒杀页面,而这个页面必须强依赖商品信息、用户信息,还有其他如让利券、成交列表等那些对秒杀不是非要不可的信息(弱依赖),这种弱依赖在紧急情况下就可以去除。

方式:给系统进行分级,例如0级系统、1级系统、2级系统、3级系统,0级系统若果是最重要的系统,这么0级系统强依赖的系统同样是最重要的系统,以这种推。

注意:0级系统要尽量减低对1级系统的强依赖,避免重要的系统被不重要的系统逼退。诸如支付系统是0级系统,而让利券是1级系统的话,在极端情况下可以把让利券给降级,避免支付系统被让利券这个1级系统给击溃。

5.不要有单点

系统中的单点可以说是系统构架上的一个三忌,由于单点意味着没有备份,风险不可控,我们设计分布式系统最重要的原则就是“消除单点”。

方式:防止将服务的状态和机器绑定,即把服务无状态化,这样服务就可以在机器中随便联通。

怎样把服务的状态和机器前馈呢?诸如把和机器相关的配置动态化,这种参数可以通过配置中心来动态推送,在服务启动时动态拉取出来,我们在这种配置中心设置一些规则来便捷地改变这种映射关系。

应用无状态化是有效防止单点的一种形式,而且像储存服务本身很难无状态化,由于数据要储存在c盘上,本身就要和机器绑定,这么这些场景通常要通过冗余多个备份的形式来解决单点问题。

2.天猫秒杀系统演化

2.1简单秒杀系统

商品订购页面降低一个“定时上架”功能,仅在秒杀开始时才让用户听到订购按键,当商品的库存售完了也就结束了。

2.210w/s秒杀系统

随着恳求量的加强(例如从1w/s到了10w/s的量级),简单的构架很快就遇见了困局,因而须要做构架整修来提高系统性能。这种构架整修包括:

1.把秒杀系统独立下来单独构建一个系统,这样可以有针对性地做优化,比如这个独立下来的系统就降低了铺家装的功能,减轻了页面的复杂度;

2.在系统布署上也独立做一个机器集群,这样秒杀的大流量就不会影响到正常的商品订购集群的机器负载;

3.将热点数据(如库存数据)单独放在一个缓存系统中,以提升“读性能”;

4.降低秒杀答题,避免有秒杀器抢单。

2.3100w/s秒杀系统

这个构架依然支持不了超过100w/s的恳求量,所以为了进一步提高秒杀系统的性能,我们又对构架做进一步升级,例如:

1.对页面进行彻底的动静分离,致使用户秒杀时不须要刷新整个页面,而只须要点击抢宝按键,以此把页面刷新的数据降到最少;

2.在服务端对秒杀商品进行本地缓存,不须要再调用依赖系统的后台服务获取数据,甚至不须要去公共的缓存集群中查询数据,这样除了可以降低系统调用,但是才能防止拖垮公共缓存集群。

3.降低系统限流保护,避免最坏情况发生。

3.高性能

3.1动静分离

何为动静数据?

所谓“动静分离”,虽然就是把用户恳求的数据(如HTML页面)界定为“动态数据”和“静态数据”。主要区别就是看页面中输出的数据是否和URL、浏览者、时间、地域相关,以及是否富含Cookie等私密数据。所谓“动态”还是“静态”,并不是说数据本身是否动静,而是数据中是否富含和访问者相关的个性化数据。

如何对静态数据做缓存呢?

第一,你应当把静态数据缓存到离用户近来的地方。常见的就三种,用户浏览器里、CDN上或则在服务端的Cache中。你应当按照情况,把它们尽量缓存到离用户近来的地方。

第二,静态化改建就是要直接缓存HTTP联接。静态化改建是直接缓存HTTP联接而不是仅仅缓存数据,如右图所示,Web代理服务器按照恳求URL,直接取出对应的HTTP响应头和响应体之后直接返回,这个响应过程简单得连HTTP合同都不用重新组装,甚至连HTTP恳求头也不须要解析。

第三,让谁来缓存静态数据也很重要。不同语言写的Cache软件处理缓存数据的效率也各不相同。以Java为例,由于Java系统本身也有其弱点(例如不擅长处理大量联接恳求,每位联接消耗的显存较多,Servlet容器解析HTTP合同较慢),所以你可以不在Java层做缓存淘宝秒杀要回答问题,而是直接在Web服务器层上做,这样你就可以屏蔽Java语言层面的一些弱点;而相比上去,Web服务器(如Nginx、Apache、Varnish)也更擅长处理大并发的静态文件恳求。

怎样做动静分离的整修?

以典型的商品详情系统为例来详尽介绍,从以下5个方面来分离出动态内容。

1.URL惟一化。商品详情系统天然地就可以做到URL惟一化,例如每位商品都由ID来标示,这么就可以作为惟一的URL标示。为何要URL惟一呢?上面说了我们是要缓存整个HTTP联接,这么以哪些作为Key呢?就以URL作为缓存的Key,比如以id=xxx这个格式进行分辨。

2.分离浏览者相关的诱因。浏览者相关的诱因包括是否已登陆,以及登陆身分等,这种相关诱因我们可以单独分拆下来,通过动态恳求来获取。

3.分离时间诱因。服务端输出的时间也通过动态恳求获取。

4.异步化地域诱因。详情页面上与地域相关的诱因弄成异步方法获取,其实你也可以通过动态恳求形式获取,只是这儿通过异步获取更合适。

5.除去Cookie。服务端输出的页面包含的Cookie可以通过代码软件来删掉,如Web服务器Varnish可以通过unsetreq.http.cookie命令除去Cookie。注意,这儿说的去除Cookie并不是用户端收到的页面就不含Cookie了,而是说,在缓存的静态数据中不富含Cookie。

怎样处理动态数据?

好多动态内容就会被页面中的其他模块用到,我们应当将这种信息JSON化(用JSON格式组织那些数据),以便捷后端获取。处理一般有两种方案:ESI(EdgeSideIncludes)方案和CSI(ClientSideInclude)方案。

ESI方案(或则SSI):即在Web代理服务器上做动态内容恳求,并将恳求插入到静态页面中,当用户领到页面时早已是一个完整的页面了。这些方法对服务端性能有些影响,并且用户体验较好。

CSI方案。即单独发起一个异步JavaScript恳求,以向服务端获取动态内容。这些方法服务端性能更佳,而且用户端页面可能会延时,体验稍差。

怎样对动静数据进行组合?

方案1:实体机单机布署

这些方案是将虚拟机改为实体机,以减小Cache的容量,但是采用了一致性Hash分组的形式来提高命中率。这儿将Cache分成若干组,是希望能达到命中率和访问热点的平衡。Hash分组越少,缓存的命中率肯定都会越高,但弱项是也会使单个商品集中在一个分组中,容易造成Cache被击穿,所以我们应当适当降低多个相同的分组,来平衡访问热点和命中率的问题。

优点:

1.没有网路困局,但是能使用大显存;

2.既能提高命中率,又能降低Gzip压缩;

3.降低Cache失效压力,由于采用定时失效形式,比如只缓存3秒钟,过期即手动失效。

缺点:

1.其实把一般只须要虚拟机或则容器运行的Java应用换成实体机,优势很显著,它会降低单机的显存容量,并且一定程度上也导致了CPU的浪费,由于单个的Java进程很难用完整个实体机的CPU。

2.一个实体机上布署了Java应用又作为Cache来使用,这导致了运维上的高复杂度,所以这是一个折中的方案。

方案2:统一Cache层

所谓统一Cache层,就是将单机的Cache统一分离下来,产生一个单独的Cache集群。统一Cache层是个更理想的可推广方案,该方案的结布光如下:

优点:

1.单独一个Cache层,可以降低多个应用接入时使用Cache的成本。这样接入的应用只要维护自己的Java系统就好,不须要单独维护Cache,而只关心怎样使用即可。

2.统一Cache的方案更便于维护,如前面强化监控、配置的手动化,只须要一套解决方案就行,统一上去维护升级也比较便捷。

3.可以共享显存,最大化借助显存,不同系统之间的显存可以动态切换,因而才能有效应对各类功击。

问题:

1.Cache层内部交换网路成为困局;

2.缓存服务器的网卡也会是困局;

3.机器少风险较大,死掉一台都会影响很大一部份缓存数据。

要解决前面那些问题,可以再对Cache做Hash分组,即一组Cache缓存的内容相同,这样才能防止热点数据过度集中造成新的困局形成。

方案3:上CDN

需解决问题:

1.失效问题。须要保证CDN可以在秒级时间内,让分布在全省各地的Cache同时失效,这对CDN的失效系统要求很高。

2.命中率问题。将数据全部放在全省的CDN上,必然引起Cache分散,而Cache分散又会造成访问恳求命中同一个Cache的可能性增加,这么命中率就成为一个问题。

3.发布更新问题。假如一个业务系统每周都有日常业务须要发布,这么发布系统必须足够简约高效,并且你还要考虑有问题时快速回滚和排查问题的简便性。

既将商品详情系统放在全省的所有CDN节点上是不太现实的,这么是否可以选择若干个节点来尝试施行呢?答案是“可以”,并且这样的节点须要满足几个条件:

1.紧靠访问量比较集中的地区;

2.离主站相对较远;

3.节点到主站间的网路比较好,但是稳定;

4.节点容量比较大,不会占用其他CDN太多的资源。

5.节点不要太多。

基于前面几个诱因,选择CDN的二级Cache比较合适,由于二级Cache数目偏少,容量也更大,让用户的恳求先回源的CDN的二级Cache中,假如没命中再回源站获取数据,布署形式如右图所示:

使用CDN的二级Cache作为缓存,可以达到和当前服务端静态化Cache类似的命中率,由于节点数不多,Cache不是很分散,访问量也比较集中,这样也就解决了命中率问题,同时还能给用户最好的访问体验,是当前比较理想的一种CDN化方案。

除此之外,CDN化布署方案还有以下几个特征:

1.把整个页面缓存在用户浏览器中;

2.假如强制刷新整个页面,也会恳求CDN;

3.实际有效恳求,只是用户对“刷新抢宝”按钮的点击。

这样就把90%的静态数据缓存在了用户端或则CDN上,当真正秒杀时,用户只须要点击特殊的“刷新抢宝”按钮,而不须要刷新整个页面。这样一来,系统只是向服务端恳求极少的有效数据,而不须要重复恳求大量的静态数据。

3.2热点数据

哪些是“热点”?

“热点操作”:大量的刷新页面、大量的添加购物车、双十一零点大量的下单

“热点数据”:用户的热点恳求对应的数据。而热点数据又分为“静态热点数据”和“动态热点数据”。

“静态热点数据”:能否提早预测的热点数据。例:买家报考;大数据提早剖析,如剖析历史成交记录、用户的购物车记录等

“动态热点数据”:不能被提早预测到的,系统在运行过程中临时形成的热点。诸如,买家在抖音上做了广告,之后商品一下就火了。

怎样发觉热点数据?

“静态热点数据”:

通过商业手段,比如强制让买家通过报考出席的形式提早把热点商品筛选下来,这些方法会降低买家的使用成本,但是实时性较差,也不太灵活。

通过技术手段提早预测,比如对卖家每晚访问的商品进行大数据估算,之后统计出TOPN的商品,我们可以觉得这种TOPN的商品就是热点商品。

“动态热点数据”:

给出一个动态热点发觉系统的具体实现:

1.建立一个异步的系统,它可以搜集交易链路上各个环节中的中间件产品的热点Key,如Nginx、缓存、RPC服务框架等这种中间件(一些中间件产品本身早已有热点统计模块)。

2.构建一个热点上报和可以根据需求订阅的热点服务的下发规范,主要目的是通过交易链路上各个系统(包括详情、购物车、交易、优惠、库存、物流等)访问的时间差,把上游早已发觉的热点透传给下游系统,提早做好保护。例如,对于大促高峰期,详情系统是最早晓得的,在统一接入层上Nginx模块统计的热点URL。

3.将上游系统搜集的热点数据发送到热点服务台,之后下游系统(如交易系统)都会晓得什么商品会被频繁调用,之后做热点保护。

用户访问商品时经过的路径有好多,我们主要是依赖上面的导购页面(包括首页、搜索页面、商品详情、购物车等)提早辨识什么商品的访问量高,通过这种系统中的中间件来搜集热点数据,并记录到日志中。

怎样处理热点数据?

处理热点数据一般有几种思路:一是优化,二是限制,三是隔离。

优化:优化热点数据最有效的办法就是缓存热点数据,假如热点数据做了动静分离,这么可以常年缓存静态数据。并且,缓存热点数据更多的是“临时”缓存,即不管是静态数据还是动态数据,都用一个队列短暂地缓存数秒钟,因为队列宽度有限,可以采用LRU淘汰算法替换。

限制:限制更多的是一种保护机制,限制的办法也有好多,比如对被访问商品的ID做一致性Hash,之后按照Hash做分桶,每位分桶设置一个处理队列,这样可以把热点商品限制在一个恳求队列里,避免因个别热点商品占用太多的服务器资源,而使其他恳求一直得不到服务器的处理资源。

隔离:秒杀系统设计的第一个原则就是将这些热点数据隔离下来,不要让1%的恳求影响到另外的99%,隔离下来后也更便捷对这1%的恳求做针对性的优化。

具体到“秒杀”业务,我们可以在以下几个层次实现隔离。

业务隔离:把秒杀弄成一种营销活动,买家要出席秒杀这些营销活动须要单独报考,从技术上来说,买家报考后对我们来说就有了已知热点,因而可以提早做好预热。

系统隔离:系统隔离更多的是运行时的隔离,可以通过分组布署的形式和另外99%分开。秒杀可以申请单独的域名,目的也是让恳求落到不同的集群中。

数据隔离:秒杀所调用的数据大部份都是热点数据,例如会启用单独的Cache集群或则MySQL数据库来放热点数据,目的也是不想0.01%的数据有机会影响99.99%数据。

其实了,实现隔离有好多种办法。例如,你可以根据用户来分辨,给不同的用户分配不同的Cookie,在接入层,路由到不同的服务插口中;再例如,你还可以在接入层针对URL中的不同Path来设置限流策略。服务层调用不同的服务插口,以及数据层通过给数据打标来分辨等等这种举措,其目的都是把早已辨识下来的热点恳求和普通的恳求区分开。

3.3流量削峰

为何要流量削峰?

一是可以让服务端处理显得愈发平稳,二是可以节约服务器的资源成本。针对秒杀这一场景,削峰从本质上来说就是更多地减缓用户恳求的发出,便于降低和过滤掉一些无效恳求,它遵照“请求数要尽量少”的原则。

流量削峰的形式有什么?

无损削峰(即不会损失用户的发出恳求):排队、答题、分层过滤。

排队

用消息队列来缓冲瞬时流量,把同步的直接调用转换成异步的间接推送.缺点:本机的消息积压达到了储存空间的上限,消息队列同样也会被压死

不仅消息队列,类似的排队方法还有好多,比如:

1.借助线程池加锁等待也是一种常用的排队方法;

2.先进先出、先进后出等常用的显存排队算法的实现方法;

3.把恳求序列化到文件中,之后再次序地读文件(比如基于MySQLbinlog的同步机制)来恢复恳求等方法。

这种方法都有一个共同特点,就是把“一步的操作”变成“两步的作”变成“两步的操作”,其中降低的一步操作拿来起到缓冲的作用。

答题

答题是为了降低订购的复杂度,进而达到两个目的。

1.避免部份卖家使用秒杀器在出席秒杀时作弊。降低答题后,下单的时间基本控制在2s后,秒杀器的下单比列也大大增长。

淘宝秒杀玩法_淘宝秒杀技巧问题_淘宝秒杀要回答问题

2.就是减缓恳求,起到对恳求流量进行削峰的作用,因而让系统才能更好地支持瞬时的流量高峰。这个重要的功能就是把峰值的下单恳求拉长,从原先的1s之内延长到2s~10s。这样一来,恳求峰值基于时间分片了。如当初支付宝的“咻一咻”、微信的“摇一摇”都是类似的形式。

秒杀答题的设计思路:

整个秒杀答题的逻辑主要分为3部份

1.题库生成模块,主要就是生成一个个问题和答案,才能避免由机器来算出结果

2.题库的推送模块,用于在秒杀答题前,把题目提早推献给详情系统和交易系统。保证每次用户恳求的题目是惟一的,目的也是避免答题作弊。

3.题目的图片生成模块,用于把题目生成为图片格式,但是在图片里降低一些干扰诱因。同样是为避免机器直接来答题。因为答题时网路比较拥挤,我们应当把题目的图片提早推送到CDN上而且要进行预热,不然的话当用户真正恳求题目时,图片可能加载比较慢,因而影响答题的体验。

我们可以把问题和答案用下边这样的key来进行MD5加密:

问题key:userId+itemId+question_Id+time+PK

答案key:userId+itemId+answer+PK

验证的逻辑如右图所示:

这儿面的验证逻辑,不仅验证问题的答案以外,还包括用户本身身分的验证,比如是否早已登陆、用户的Cookie是否完整、用户是否重复频繁递交等。

不仅做正确性验证,我们还可以对递交答案的时间做些限制,比如从开始答题到接受答案要超过1s,由于大于1s是人为操作的可能性很小,这样也能避免机器答题的情况。

分层过滤

如果恳求分别经过CDN、前台读系统(如商品详情系统)、后台系统(如交易系统)和数据库这几层,这么:

1.大部份数据和流量在用户浏览器或则CDN上获取,这一层可以拦截大部份数据的读取;

2.经过第二层(即前台系统)时数据(包括强一致性的数据)尽量得走Cache,过滤一些无效的恳求;

3.再到第三层后台系统,主要做数据的二次检验,对系统做好保护和限流,这样数据量和恳求就进一步降低;

4.最后在数据层完成数据的强一致性校准。

分层过滤的核心思想是:在不同的层次尽可能地过滤掉无效恳求,让“漏斗”最末端的才是有效恳求。而要达到这些疗效,我们就必须对数据做分层的校准。

分层校准的基本原则是:

1.将动态恳求的读数据缓存(Cache)在Web端,过滤掉无效的数据读;

2.对读数据不做强一致性校准,降低由于一致性校准形成困局的问题;

3.对写数据进行基于时间的合理分片,过滤掉过期的失效恳求;

4.对写恳求做限流保护,将超出系统承载能力的恳求过滤掉;

5.对写数据进行强一致性校准,只保留最后有效的数据。

分层校准的目的是:

在读系统中,尽量降低因为一致性校准带来的系统困局,并且尽量将不影响性能的检测条件提早,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否早已结束、是否非法恳求、营销等价物是否充足等;

在写数据系统中,主要对写的数据(如“库存”)做一致性检测,最后在数据库层保证数据的最终确切性(如“库存”不能减为正数)。

4.一致性--减库存

减库存有哪几种方法?

下单减库存,即当卖家下单后,在商品的总库存中除以卖家订购数目。下单减库存是最简单的减库存形式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超买的情况。并且你要晓得,有些人下完单可能并不会付款。

付款减库存,即卖家下单后,并不立刻减库存,而是等到有用户付款后才真正减库存,否则库存仍然保留给其他卖家。但由于付款时才减库存,假如并发比较高,有可能出现卖家下单后付不了款的情况,由于可能商品早已被其他人买走了。

预扣库存,这些方法相对复杂一些,卖家下单后,库存为其保留一定的时间(如10分钟),超过这个时间,库存将会手动释放,释放后其他卖家就可以继续订购。在卖家付款前,系统会校准该订单的库存是否还有保留:假如没有保留,则再度尝试预扣;假如库存不足(也就是预扣失败)则不容许继续付款;假如预扣成功,则完成付款并实际地乘以库存。

减库存可能存在的问题?

下单减库存:竞对恶意下单,不真正付款,让商品库存减为零,不能正常售卖。

付款减库存:库存超买,致使好多卖家下单成功并且付不了款,卖家的购物体验比较差。

预扣库存:恶意卖家完全可以在10分钟后再度下单,或则采用一次下单好多件的形式把库存减完。解决方法:给常常下单不付款的卖家进行辨识打标;给个别类目设置最大订购件数;重复下单不付款的操作进行次数限制等

小型秒杀中怎样减库存?

秒杀商品采用“下单减库存”更加合理。通常都是“抢到就是赚到”,所以成功下单后却不付款的情况比较少,再加上店家对秒杀商品的库存有严格限制,因为“下单减库存”比“预扣库存”以及涉及第三方支付的“付款减库存”在逻辑上更为简单,所以性能上更占优势。

怎样保证库存不为正数?

1.应用程序中通过事务来判定,即保证减后库存不能为正数,否则就回滚

2.接设置数据库的数组数据为无符号整数,这样减后库存数组值大于零时会直接执行SQL句子来报错

3.使用CASEWHEN判定句子,比如这样的SQL句子UPDATEitemSETinventory=CASEWHENinventory>=xxxTHENinventory-xxxELSEinventoryEND

秒杀减库存的极至优化

1.能够把秒杀商品减库存直接放在缓存系统中实现,也就是直接在缓存中减库存或则在一个带有持久化功能的缓存系统(如Redis)中完成呢?

假如你的秒杀商品的减库存逻辑特别单一,例如没有复杂的SKU库存和总库存这些联动关系的话,我认为完全可以。并且假如有比较复杂的减库存逻辑,或则须要使用事务,你还是必须在数据库中完成减库存。

2.单个热点商品会影响整个数据库的性能,可以把热点商品放在单独的热点库中,但没有解决并发锁的问题,要解决并发锁的问题,有两种办法:

应用层做排队:根据商品维度设置队列次序执行,这样能降低同一台机器对数据库同一行记录进行操作的并发度,同时也能控制单个商品占用数据库联接的数目,避免热点商品占用太多的数据库联接。

数据库层做排队:应用层只能做到单机的排队,并且应用机器数本身好多,这些排队方法控制并发的能力一直有限,所以假如能在数据库层做全局排队是最理想的。阿里的数据库团队开发了针对这些MySQL的InnoDB层上的补丁程序(patch),可以在数据库层上对单行记录做到并发排队。

5.高可用

构架阶段:构架阶段主要考虑系统的可扩充性和容错性,要防止系统出现单点问题。诸如多机房单元化布署,虽然某个城市的某个机房出现整体故障,一直不会影响整体网站的运转。

编码阶段:编码最重要的是保证代码的强壮性,比如涉及远程调用问题时,要设置合理的超时退出机制,避免被其他系统击溃,也要对调用的返回结果集有预期,避免返回的结果超出程序处理范围,最常见的做法就是对错误异常进行捕获,对未能意料的错误要有默认处理结果。

测试阶段:测试主要是保证测试用例的覆盖度,保证最坏情况发生时,我们也有相应的处理流程。

发布阶段:发布时也有一些地方须要注意,由于发布时最容易出现错误,因而要有紧急的回滚机制。

运行阶段:运行时是系统的常态,系统大部分时间就会处于运行态,运行态最重要的是对系统的监控要确切及时,发觉问题才能确切报案而且报案数据要确切详尽,以易于排查问题。

故障发生:故障发生时首先最重要的就是及时补仓,比如因为程序问题引起商品价钱错误,那就要及时下架商品或则关掉订购链接,避免引起重大资产损失。之后就是要才能及时恢复服务,并定位缘由解决问题。

运行阶段处理举措:降级、限流和拒绝服务

降级

所谓“降级”,就是当系统的容量达到一定程度时,限制或则关掉系统的个别非核心功能,进而把有限的资源保留给更核心的业务。

降级方案:当秒杀流量达到5w/s时,把成交记录的获取从展示20条降级到只展示5条。“从20改到5”这个操作由一个开关来实现,也就是设置一个才能从开关系统动态获取的系统参数。

开关系统示意图:

一部份是开关控制台,它保存了开关的具体配置信息,以及具体执行开关所对应的机器列表;

另一部份是执行下发开关数据的Agent淘宝秒杀要回答问题,主要任务就是保证开关被正确执行,虽然系统重启后也会生效。

降级的核心目标是牺牲次要的功能和用户体验来保证核心业务流程的稳定,是一个不得涕泣为之的措施。

限流

限流就是当系统容量达到困局时,我们须要通过限制一部分流量来保护系统,并做到既可以人工执行开关,也支持手动化保护的举措。

总体来说,限流既可以是在顾客端限流,也可以是在服务端限流。据悉,限流的实现方法既要支持URL以及方式级别的限流,也要支持基于QPS和线程的限流。

在限流的实现手段上来讲,基于QPS和线程数的限流应用最多,最大QPS很容易通缺相测提早获取,比如我们的系统最高支持1wQPS时,可以设置8000来进行限流保护。线程数限流在顾客端比较有效,比如在远程调用时我们设置联接池的线程数,超出这个并发线程数,超出这个并发线程恳求,就将线程进行排队或则直接超时遗弃。

限流无疑会影响用户的正常恳求,所以必然会造成一部份用户恳求失败,因而在系统处理这些异常时一定要设置超时时间,避免因被限流的恳求不能fastfail(快速失败)而重创系统。

拒绝服务

假如限流还不能解决问题,最后一招就是直接拒绝服务了。

当系统负载达到一定阀值时,比如CPU使用率达到90%或则系统load值达到2*CPU核数时,系统直接拒绝所有恳求,这些方法是最暴力但也最有效的系统保护方法。诸如秒杀系统,我们在如下几个环节设计过载保护:在最后端的Nginx上设置过载保护,当机器负载达到某个值时直接拒绝HTTP恳求并返回503错误码,在Java层同样也可以设计过载保护。

拒绝服务可以说是一种不得已的兜底方案,用以避免最坏情况发生,避免因把服务器压跨而长时间彻底未能提供服务。像这些系统过载保护其实在过载时未能提供服务,并且系统一直可以运作,当负载增长时又很容易恢复,所以每位系统和每位环节都应当设置这个兜底方案,对系统做最坏情况下的保护。

淘宝秒杀要回答问题
上一篇:五公里胜于三公里 下一篇:没有了