服务器的资源是恒定的,你用或者不用,它就在原地,处理能力不会改变。所以出现峰值的话,就很容易会导致忙到处理不过来,甚至让服务器出现宕机情况,虽然大多数时候不会有过多的业务需要处理。但是为了保证服务质量,很多服务器的资源只能够按照峰值的时候来设置,而这样就会导致服务器资源的浪费。
如12306的抢票、双十一的购物,都会产生大量的请求同时涌向服务器,就会导致一个特别高的流量峰值,它对服务器资源的消耗是瞬时的。
流量削峰就好比因为存在早高峰和晚高峰的问题,所以有了错峰限行的解决方案。
削峰的存在,一是可以让服务端处理变得平稳,二是可以节省服务器的资源成本。
针对秒杀这一场景,削峰从本质上来说就是更多地去延缓用户发出的请求,以便减少和过滤掉一些无效的请求,它遵从【请求数要尽量少】的原则。
流量削峰主要有三种操作思路,一是排队,二是答题,三是分层过滤,这三种方式都是无损(即不会损失用户的请求发出)的实现方案。当然,还有些有损的实现方案,关于稳定性的一些方法,比如限流和机器负载保护等一些强制措施也能达到削峰保护的目的,只是这些都是一些不得已的措施。
要对流量进行削峰,最容易想到的解决方案就是用消息队列来缓冲瞬时流量,把同步的直接调用转换成异步的间接推送,中间通过一个队列在一端承接瞬时的流量洪峰,另一端平滑地将消息推送出去。在这里,消息队列就像一个水库一样,拦截上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。
答题功能,是为了增加购买的复杂度,从而达到两个目的。
第一个目的是防止部分买家在参加秒杀的时候使用秒杀器作弊。在2011年秒杀非常火的时候,秒杀器也比较猖獗,因而并没有达到全民参与和营销推广的目的,所以系统就增加了答题功能来限制秒杀器。在增加了答题功能后,下单的时间基本控制在2s后,秒杀器的下单比例也大大下降。
第二个目的是为了延缓请求,起到对请求流量进行削峰的作用,从而使系统能够更好地支持瞬时的流量高峰。这个重要的功能就是把峰值的下单请求拉长,从先前的1s之内延长到2s~10s。这样一来,请求峰值就基于时间分片了。这个时间的分片对服务端处理并发非常重要,会大大减轻压力。而且由于请求具有先后顺序,靠后的请求到来时自然就没有库存了,因此根本到不了最后的下单步骤,所以真正的并发写就非常有限了。这种设计思路目前用得非常普遍,如支付宝的【咻一咻】和微信【摇一摇】,都是类似的方式。
整个秒杀答题功能的逻辑,主要可以分为3个部分。
1.题库生成模块。这个部分主要就是生成一个个问题和答案,题目和答案本身都不需要太复杂,重要的能防止由机器来算出结果,防止秒杀器答题。
2.题库推送模块。这个部分用于在秒杀答题前,把题目提前推送给详情系统和交易系统。实时推送是为了保证每次用户请求的题目是唯一的,防止答题作弊。
3.题目的图片生成模块,用于把题目生成为图片格式,并且在图片里增加一些干扰因素。这也同样是为了防止机器直接来答题,它要求只有人才能理解题目本身的含义。这里还要注意一点,由于答题时网络比较拥挤,应该把题目的图片提前推送到CDN上并且要进行预热,不然的话当用户真正请求题目时,图片可能加载比较慢,从而影响答题的体验。
事实上,真正答题的逻辑是比较简单的,比较容易理解。只要将用户提交的答案与题目对应的答案做比较,比较通过则继续进行下一步逻辑,否则就失败。
假如请求分别经过CDN、前台读系统(如商品详情系统)、后台系统(如交易系统)和数据库这层,那么,大部分数据和流量在用户浏览器或CDN上获取,这一层可以拦截大部分数据的读取;经过第二层(即前台系统)时,数据(包括强一致性的数据)都尽量走Cache,过滤一些无效的请求;再到第三层的后台系统,主要做数据的二次校验,对系统做好保护和限流,这样数据量和请求就进一步减少;最后在数据层完成数据的强一致性校验就好了。
这样的话,就像漏斗一样,尽量把数据量和请求量一层一层地过滤和减少。
分层过滤的核心思想是在不同的层次尽可能地过滤掉无效的请求,让漏斗最末端的才是有效请求。而要达到这种效果,我们就必须对数据做分层的校验。
基本原则:
1.将动态请求的读数据缓存(Cache)在Web端,过滤掉无效的数据读取。
2.对读数据不做强一致性校验,减少因为一致性校验产生性能瓶颈的问题。
3.对写数据进行基于时间的合理分片,过滤掉过期的失效请求。
4.对写请求做限流保护,将超出系统承载能力的请求过滤掉。
5.对写数据进行强一致性校验,只保留最后有效的数据。
分层校验的目的是在读系统中尽量减少由于一致性校验带来的系统瓶颈,但是尽量将不影响性能的检查条件提前,比如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求、营销等价物是否充足等。而在写数据系统中,主要对写的数据(如库存)做一致性检查,最后在数据库层保证数据的最终准确性(如库存不能为负数)。