SREcon 是由计算机科学领域知名机构USENIX主办,聚焦网站可靠性、系统工程、以及复杂分布式系统相关的运维行业技术盛会,今年SREcon17大会 Asia/Australia站于当地时间5月22日-24日在新加坡举行。阿里中间件(Aliware)团队高级技术专家张军(花名游骥)和林佳梁(花名子矜),受邀在本次大会上给现场听众分享了阿里巴巴容量规划和全链路压测方面的技术进展。

 


容量规划的由来


阿里巴巴有着非常丰富的业务形态,每种业务都由一系列不同的业务系统来提供服务,每个业务系统都分布式地部署在不同的机器上。随着业务的发展,特别是在大促营销等活动场景下(比如双11),需要为每个业务系统准备多少机器对于阿里巴巴技术团队来说是一大难题。


“容量规划”正是为解决这个难题而诞生,容量规划的目的在于让每一个业务系统能够清晰地知道:什么时候应该加机器、什么时候应该减机器?双11等大促场景需要准备多少机器,既能保障系统稳定性、又能节约成本?

 

Capacity Planning

Business Requirements

Business growth

New business

Promotions                           Current e-business system

                                    APP1 APP2 APP3 APP4...APPN

                                    Service1 Serivce2 Serivce....n

                                            service serivce service

                                        cache DB DBn


when scalability is needed? how many machines? correct ratio fro each server?

capacity planning is the process of determining the capacity needed by a complexity

distributed system to meet the workload with guarantee on certain level of performance.


容量规划四步走


在双11等大促场景的准备过程当中,容量规划一般分为四个阶段:


第一个阶段为业务流量预估阶段,通过历史数据分析未来某一个时间点业务的访问量会有多大;

第二个阶段为系统容量评估阶段,初步计算每一个系统需要分配多少机器;

第三个阶段为容量的精调阶段,通过全链路压测来模拟大促时刻的用户行为,在验证站点能力的同时对整个站点的容量水位进行精细调整;

第四个阶段为流量控制阶段,对系统配置限流阈值等系统保护措施,防止实际的业务流量超过预估业务流量的情况下,系统无法提供正常服务。


Flow Control Fast Recovery Traffice Model Historical 

Data Prediction Alogrithm 

Single Macheine App Capacity Verify Fine Tune

Full Chain Stress Test Capacity Estimation 


在第一个阶段当中,通过合适的预测算法和丰富的历史数据,通常能够比较准确的预估业务的访问量。即使在第一阶段预估的业务访问量跟实际的存在误差,通过第四阶段的流量控制也能够确保站点始终处于良好的服务状态。做完业务访问量的预估之后,容量规划进入第二阶段,为系统进行容量的初步评估。如何通过精准的容量评估,用最小的成本来支撑好预估的业务量是这个阶段的核心问题。


要计算一个系统需要多少台机器,除了需要知道未来的业务调用量之外,还有一个更重要的变量,就是单台机器的服务能力。获取单台机器的服务能力在阿里巴巴是通过单机压测的方式来获取。在阿里巴巴,为了精准地获取到单台机器的服务能力,压力测试都是直接在生产环境进行,这有两个非常重要的原因:单机压测既需要保证环境的真实性,又要保证流量的真实性。否则获取到的单台机器服务能力值将会有比较大的误差,影响到整个容量规划的准确性。


生产环境进行单台机器压力测试的方式主要分为4种:


1、模拟请求,通过对生产环境的一台机器发起模拟请求调用来达到压力测试的目的;

2、复制请求,通过将一台机器的请求复制多份发送到指定的压测机器;

3、请求转发,将分布式环境中多台机器的请求转发到一台机器上;

4、调整负载均衡,修改负载均衡设备的权重,让压测的机器分配更多的请求。

 

模拟请求的实现比较简单,也有非常多的开源或者商业工具可以来做请求模拟,比如apache ab、webbench、httpload、jmeter、loadrunner。通场情况下,新系统上线或者访问量不大的系统采用这种方式来进行单机压测。模拟请求的缺点在于,模拟请求和真实业务请求之间存在的差异,会对压力测试的结构造成影响。模拟请求的另一个缺点在于写请求的处理比较麻烦,因为写请求可能会对业务数据造成污染,这个污染要么接受、要么需要做特殊的处理(比如将压测产生的数据进行隔离)。


为了使得压测的请求跟真实的业务请求更加接近,在压测请求的来源方式上,我们尝试从真实的业务流量进行录制和回放,采用请求复制的方式来进行压力测试。请求复制的方式比请求模拟请求方式的准确性更高,因为业务的请求更加真实了。


从不足上来看,请求复制同样也面临着处理写请求脏数据的问题,此外复制的请求必须要将响应拦截下来,所以被压测的这台机器需要单独提供,且不能提供正常的服务。请求复制的压力测试方式,主要用于系统调用量比较小的场景。


对于系统调用量比较大的场景,我们有更好的处理办法。其中的一种做法我们称为请求的引流转发,阿里巴巴的系统基本上都是分布式的,通过将多台机器的请求转发到一台机器上,让一台机器承受更大的流量,从而达到压力测试的目的。


请求的引流转发方式不仅压测结果非常精准、不会产生脏数据、而且操作起来也非常方便快捷,在阿里巴巴也是用的非常广泛的一种单机压测方式。当然,这种压测方式也有一个前提条件就是系统的调用量需要足够大,如果系统的调用量非常小,即使把所有的流量都引到一台机器,还是无法压测到瓶颈。


与请求引流转发的方式类似,最后一种压测方式同样是让分布式环境下的某一台机器分配更多的请求。不同的地方在于采用的方式是通过去调整负载均衡设备的权重。调整负载均衡方式活的的压测结果非常准确、并且不会产生脏数据。前提条件也需要分布式系统的调用量足够大。


在阿里巴巴,单机压测有一个专门的压测平台。压测平台在前面介绍的4种压测方式基础上,构件了一套自动化的压测系统。在这个系统上,可以配置定时任务定期对系统进行压测,也可以在任意想压测的时间点手动触发一次压测。


在进行压测的同时,实时探测压测机器的系统负载,一旦系统负载达到预设的阈值即立刻停止压测,同时输出一份压测报告。因为是在生产环境进行压测,我们必须非常小心,保障压测过程不影响到正常的业务。在单机压测平台上,每个月将进行5000次以上的压测,系统发布或者大的变更都将通过单机压测来验证性能是否有变化,通过单机压测获取的单机服务能力值也是容量规划一个非常重要的参考依据。


有了预估的业务访问量,也知道了系统单台机器的服务能力,粗略的要计算需要多少台机器就非常简单了。最小机器数 = 预估的业务访问量 / 单机能力。通常情况下,我们会预留少量的buffer来防止评估的误差和意外情况。


为什么需要全链路压测?



Single point approach is totally different from "scenarios" 

进行到这一步,我们已经完成了系统容量的粗略评估,然而做到这一步是不是就够了呢?过去的教训曾经狠狠地给我们上了一课。


我们对每一个系统都做好了粗略的容量计算,以为一切都会比较顺利了,可是真实场景并非如此,当双11的零点到来的时候,许多系统的运行情况比我们想象的要更坏。原因在于真实的业务场景下,每个系统的压力都比较大,而系统之间是有相互依赖关系的,单机压测没有考虑到依赖环节压力都比较大的情况,会引入一个不确定的误差。这就好比,我们要生产一个仪表,每一个零件都经过了严密的测试,最终把零件组装成一个仪表,仪表的工作状态会是什么样的并不清楚。


事实上我们也有过血的教训。在2012年的双11 零点,我们一个系统的数据库的网卡被打满了,从而导致部分用户无法正常购物,尽快当时我们做了非常充分的准备,但还有一些事情是我们没考虑到的。


需要怎么样才能解决这个问题?在2013年的双11备战过程当中,在很长一段时间内这都是我们面临的一个难题。在中国,学生通常都会有期末考试,为了在期末考试中取得比较好的成绩,老师通常会让学生们在考试前先做几套模拟题。


双11对我们的系统来说就是一年一度的期末考试,所以我们冒出了这么一个想法:“如果能让双11提前发生,让系统提前经历双11的模拟考验,这个问题就解决了”。通过对双11 零点的用户行为进行一次高仿真的模拟,验证整个站点的容量、性能和瓶颈点,同时验证之前进行的容量评估是否合理,不合理的地方再进行适当的微调。


我们为此研发了一套新的压测平台—“全链路压测”。双11的模拟可不是一件简单的事情,上亿的用户在阿里巴巴平台上挑选、购买好几百万种不同类型的商品,场景的复杂性非常高。有三个最主要的难点需要解决:


1、用于的请求量非常大,在双11 零点,每秒的用户请求数超过1000w;

2、模拟的场景要跟双11 零点尽可能的贴近,如果模拟的场景跟双11 零点差距太大,将不具备实际的参考价值,而双11 零点的业务场景非常复杂;

3、我们需要在生产环节去模拟双11,如何去做到模拟的用户请求不对正常的业务和数据造成影响。


为了能够发出每秒1000w以上的用户请求,全链路压测构件了一套能够发出超大规模用户请求的流量平台。流量平台由一个控制节点和上千个worker节点组成,每一个worker节点上都部署了我们自己研发的压测引擎。


压测引擎除了需要支持阿里巴巴业务的请求协议,还需要具备非常好的性能,要不然1000w的用户请求,我们将无法提供足够多的worker节点。上千个压测引擎彼此配合、紧密合作,我们能像控制一台机器一样控制整个压测集群,随心所欲的发出100w/s或者1000w/s的用户请求。

 

Flow control platform

Telecom CDN Unicom CDN Mobile CDN Node Education CDN Node

Flow engine cluster


1000w+/s的用户请求量不仅要能够发送出来,而且还需要跟双11的用户行为尽可能的接近,而双11是一个非常复杂的业务场景。为了使得模拟能够更加真实,我们做了非常多的工作。首先,我们从生产环境提取一份跟双11 同等数量级的基础数据(包含:买家、卖家、店铺、商品、优惠等等),做好筛选和敏感字段的脱敏,作为全链路压测的基础数据。然后基于这些基础数据,结合前几年的历史数据,通过相应的预测算法,得到今年双11的业务模型。


双11的业务模型包含100多个业务因子,比如:买家数量、买家种类、卖家数量、卖家种类、商品数量、商品种类,pc和无线的占比,购物车里的商品数量,每一种业务类型的访问量级等等)。有了业务模型之后,再根据业务模型构造相应的压测请求,最终将压测请求上传到压测引擎。


全链路压测直接在生产环境进行双11的模拟,在前面的单机压测方式中也有提到,对于模拟请求的方式,需要考虑脏数据的处理方式。全链路压测的所有数据都在生产环境做了数据隔离,包含存储、缓存、消息、日志等一系列的状态数据。在压测请求上会打上特殊的标记,这个标记会随着请求的依赖调用一直传递下去,任何需要对外写数据的地方都会根据这个标记的判断写到隔离的区域,我们把这个区域叫做影子区域。全链路压测对粗略的容量评估起到了精调的作用,使双11 零点的各种不确定性变的更加确定。


Form Basic Data 

Estimate Model 

Form Test Request         Business Warm-up 

                                   Upload Test Request

                                    Small Traffic Pre-run

                                                                        Formal Stress Test

                                                                        Adjust Machine Ratio

                                                                        Generate Test Report


 我们在2013年双11前夕的全链路压测过程当中共发现了700多个系统问题,2014、2015、2016同样也发现了好几百个问题。这些问题如果没有在全链路压测的过程当中被发现,很有可能会在双11 零点的真实业务场景当中暴露出来,将造成严重的可用性影响。


意外的甜蜜,超限后的流量控制如何做?


前面章节我们讨论的都是”容量规划”,我们知道容量规划是基于一套精密的业务模型,而这个业务模型是根据历年来的大促数据,以及复杂的预测模型推算出来的。然而,不论这个模型多么强壮,它始终是一个预测。这就意味着我们存在着预测和现实流量有误差。

这个并不仅仅是一个担心,这个发生过非常多次。


最近的一个例子是在16年的双11,我们为某一个重要的场景预备了足以应付16.2万每秒的峰值,然而那天的峰值实际上到达了20万每秒,超过我们准备能力将近13%,你可能觉得这只会对峰值产生影响,这些额外的2W请求马上就会被消耗掉,但并不是你想的这样。


当一台机器超负荷运转的时候,这台处理请求的时间会变长。这会给用户带来不好的体验,用户会试图重复提交请求,这无形中又给系统带来了更多的请求压力。随着请求堆积的月来越多,系统性能会逐渐下降甚至无法响应新的请求。


当一台机器挂掉以后,负载均衡会把请求重定向到另外的机器上去,这又无形中给别的机器带来了更多的任务,而这些机器也处于一个饱和的状态,很快也会像第一台机器一样,也无法响应新的请求。


就这样,在很短的时间之内,越来越多的机器会停止响应,最终导致整个集群都无法响应。这就使我们常常说的“雪崩效应”。一旦“雪崩”发生,就很难停止。我们必须有一个有效的机制,来监控和控制进入的流量,来防止灾难的发生。


然而,流控并不仅仅用于流量高峰,它在很多的场景都可能用的到。比如在一个业务的链路上,有一个下游系统出现了问题,响应时间变得很长。这个问题在链路上会被放大,甚至导致整个链路不可用。这意味着流控也需要可以根据响应时间来控制系统的健康,当一个应用响应的时间超过阈值,我们可以认为这个应用不可控,应该迅速将它降级。


除了流控的激发原因之外,流控也可以灵活的定义流控的方式。不同的业务场景,可以采取不同的流控方式。比如说,对于有的应用,我们可以简单的丢弃这个请求,有的应用,则需要对下游应用进行降级,甚至直接加入黑名单。而有的应用,则需要把这些多余的请求排队,等到高峰期过后,系统没有那么忙碌之后,再逐步消耗这些流量。


所以,我们最终的流控框架可以从三个纬度着手,运行状况,调用关系,流控方式。应用可以灵活的根据自己的需求,任意组合。

 


下面这个是我们流控的架构图:

 


第一步,我们在程序入口给所有的方法都进行埋点;

第二步,我们把这些埋点方法的运行状态,调用关系统计记录下来;

第三步,我们通过从预设好的规则中心接收规则,来根据第二步中统计到的系统状态进行控制。


然而,当系统发生流控的时候,系统虽然是安全的,但是它始在一个“受损”状态下运行。所以我们也在问题排除之后,解除流量控制。用我们上面的场景作为例子。一个链路上的一个下游应用出现了问题,导致响应时间变长,从而导致上游应用的系统负载过高。过了一会儿之后,这个下游应用恢复了,响应时间大大缩短。然而这个时候,上游应用的负载并不能马上恢复,因为进来的请求已经堆积了一段时间了。


这就意味着,如果我们采用传统的方式,用系统负载来判断是否应该恢复流控,那么即使问题已经修复,系统地负载仍然处于一个比较高的状态。这样就会导致系统恢复慢。既要迅速恢复,同时也要系统稳定。最后我们采取的方式是,让rt,load,允许通过的qps达到动态平衡。



 让我们来看一下最后取得的效果。用了新的算法之后,我们可以看到系统稳定在一定的范围之内,同时当问题机器恢复之后,流量也能够很快的恢复。



从近几年双11 零点的业务稳定性上来看,全链路压测是一个明显的分水岭,在全链路压测之后整个站点的稳定性明显好于全链路压测之前。全链路压测已经成为阿里巴巴大促备战的必要环节,无论是双11大促、双12大促,还是平时一些比较小的促销活动,每一次活动之前都会进行好几轮的全链路压测来对系统进行一次全方位的模拟验证,提前暴露各个环节的问题。全链路压测的诞生使得阿里大促备战的系统稳定性有了质的提升,被誉为大促备战的核武器。


除了全链路压测来验证我们的容量规划的正确性以外,流量控制的策略在我们的大促技术规划时也很重要,限流框架通过 自由组合运行状态,调用链路,限流措施的灵活组合,覆盖了多种业务场景。同时,通过动态平衡,可以做到快恢复,最低的减低对用户使用体验的冲击。流量控制和流量压测两者结合,让我们的系统稳定健康地渡过各种极限业务场景。


此外,基于阿里在双11大促上的多年的系统高可用保障经验,全链路压测服务6月份即将在阿里云上线(在原有云产品PTS的基础上进行全方位升级),通过模拟海量用户的大流量场景,全方位验证站点各个环节的可用性。压测平台具备千万/秒的用户流量构造能力;从全国各地的CDN节点发起请求,最真实地模拟用户行为;采用直接压测生产环境的方式,精准探测站点的服务能力和性能瓶颈;压测流量与正常流量隔离、不对线上正常的业务和数据造成污染。欢迎大家关注和试用!