全链路压测及阿里全链路压测详解

一、前言

很多公司有线下性能测试,那为什么还要做全链路压测呢,全链路能解决一般性能测试的什么问题呢?我认为在每个环境做性能测试是相互补充的过程。在线下的性能测试,由于机器监控,部署迅速以及相应的权限充足,我们可以迅速定位到一些性能bug,如内存泄漏,死锁,超卖等问题,但是线下的机器达到的指标不能准确的反馈线上的实际情况,我们并不能简单通过一些充满大量经验值的公式去推算,这样的结果和拍脑袋也没啥太大差异,再加上线下环境大多以分链路、模块压测为主,所以全链路压测在这样的背景下就诞生了,我们的前提是在线下已经模块压测完成,无明显瓶颈的情况下开展,在线上进行链路的充分模拟压测。

二、什么是全链路压测

全链路压测就是基于实际的生产业务场景、系统环境,模拟海量的用户请求和数据对整个业务链进行压力测试,并持续调优的过程。

三、全链路压测解决什么问题

针对业务场景越发复杂化、海量数据冲击下整个业务系统链的可用性、服务能力的瓶颈,让技术更好的服务业务,创造更多的价值。

四、面对的问题点以及解决方案

1、业务模型梳理

首先应该明确的是:全链路压测针对的是现代越来越复杂的业务场景和全链路的系统依赖。所以首先应该将核心业务和非核心业务进行拆分,确认流量高峰针对的是哪些业务场景和模块,针对性的进行扩容准备,而不是为了解决海量流量冲击而所有的系统服务集群扩容几十倍,这样会造成不必要的成本投入。

2、数据模型构建

数据构建和准备,应该考虑这几点问题:

①、数据的真实性和可用性

可以从生产环境完全移植一份当量的数据包,作为压测的基础数据,然后基于基础数据,通过分析历史数据增长趋势,预估当前可能的数据量;

②、数据脱敏

基于生产环境的全链路压测,必须考虑的一点是不能产生脏数据,以免对生产造成影响,影响用户体验等,因此在数据准备时需要进行数据脱敏;

③、数据隔离

同样,为了避免造成脏数据写入,可以考虑通过压测数据隔离处理,落入影子库,mock对象等手段,来防止数据污染;

3、压测工具选型

全链路压测应对的都是海量的用户请求冲击,可以使用分布式压测的手段来进行用户请求模拟,目前有很多的开源工具可以提供分布式压测的方式,比如jmeter、Ngrinder、locust等。可以基于这些压测工具进行二次开发,由Contorller机器负责请求分发,agent机器进行压测,然后测试结果上传Contorller机器。
考虑到压测量较大的情况下回传测试结果会对agent本身造成一定资源占用,可以考虑异步上传,甚至事务补偿机制。

4、压测环境搭建

全链路压测都是基于生产环境,解决了业务模型和数据以及压测工具选型开发,就要考虑系统扩容和风险规避了,比如压测不能影响实际的生产业务运行,还有资源申请等。重新搭建一套完全匹配生产环境的压测环境,成本太高,且需求频次较低,投入成本太大。

5、系统容量规划

前面提到了业务拆分和流量预估,在系统容量规划阶段,首先应该对单个接口单个服务进行基准测试,调整配置参数,得到一个基准线,然后进行分布式集群部署,通过nginx负载均衡。
至于扩容,要考虑到服务扩容和DB资源扩容,以及服务扩容带来的递减效应。
至于大流量冲击情况下,可以考虑队列等待、容器锁、长连接回调、事务降级等方式来解决。

6、测试集群部署

能做全链路压测的业务系统基本都是分布式系统架构,这时服务集群部署和负载均衡就是需要实现和考虑的技术点。
需要解决的问题有:

①、服务间通信问题
一般通信方式有两种:同步和异步。

  • 同步调用:

    REST(JAX-RS,Spring Boot)
    RPC(Thrift, Dubbo)

  • 异步调用:

    (Kafka, Notify, MetaQ)

区别:

  • 同步调用一致性强,但是要考虑性能和调用失败的事务处理。
  • 异步调用的话,可以降低服务间的耦合,提升性能体验,但是一致性是需要解决的。

②、负载均衡问题

需要将大流量冲击均匀的分发给集群上的每台机器,目前比较优秀的负载均衡服务器是nginx,但nginx的部署貌似也存在一些问题,我们公司之前就遇到过订单重复问题。

③、容灾问题

需要确保的一点是:当服务中的某台或者某部分服务宕机,可以及时的进行服务转发,而不至于连锁反应下整个系统链路的服务挂掉。

7、数据收集监控
  • 压测数据收集,需要由agent机回送给Contorller机器,但数据量过大会占用一定的资源,可以考虑异步实现测试结果回送。

  • 监控,现在有很多优秀的专业监控工具,比如Nmon、Zabbix,全链路监控工具Zipkin、PinPoint以及携程开源的全链路监控工具CAT。或者可以针对需要,二次开发JVM自带的一些监控工具,做到实时全方位监控。

五、例:阿里全链路压测

为什么需要容量规划?

阿里巴巴有着非常丰富的业务形态,每种业务都由一系列不同的业务系统来提供服务,每个业务系统都分布式地部署在不同的机器上。随着业务的发展,特别是在大促营销等活动场景下(比如双11),需要为每个业务系统准备多少机器对于阿里巴巴技术团队来说是一大难题。“容量规划”正是为解决这个难题而诞生,容量规划的目的在于让每一个业务系统能够清晰地知道:什么时候应该加机器、什么时候应该减机器?双 11 等大促场景需要准备多少机器,既能保障系统稳定性、又能节约成本
在这里插入图片描述

容量规划四步骤

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

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

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

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

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

    在第一个阶段当中,通过合适的预测算法和丰富的历史数据,通常能够比较准确地预估业务的访问量。即使在第一阶段预估的业务访问量跟实际的存在误差,通过第四阶段的流量控制也能够确保站点始终处于良好的服务状态。做完业务访问量的预估之后,容量规划进入第二阶段,为系统进行容量的初步评估。如何通过精准的容量评估,用最小的成本来支撑好预估的业务量是这个阶段的核心问题。
    要计算一个系统需要多少台机器,除了需要知道未来的业务调用量之外,还有一个更重要的变量,就是单台机器的服务能力。获取单台机器的服务能力在阿里巴巴是通过单机压测的方式来获取。**在阿里,为了精准地获取到单台机器的服务能力,压力测试都是直接在生产环境进行,这有两个非常重要的原因:单机压测既需要保证环境的真实性,又要保证流量的真实性。**否则获取到的单台机器服务能力值将会有比较大的误差,影响到整个容量规划的准确性。

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

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

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

  • 复制请求:通过将一台机器的请求复制多份发送到指定的压测机器

    为了使得压测的请求跟真实的业务请求更加接近,在压测请求的来源方式上,我们尝试从真实的业务流量进行录制和回放,采用请求复制的方式来进行压力测试。请求复制的方式比请求模拟请求方式的准确性更高,因为业务的请求更加真实了。从不足上来看,请求复制同样也面临着处理写请求脏数据的问题,此外复制的请求必须要将响应拦截下来,所以被压测的这台机器需要单独提供,且不能提供正常的服务。请求复制的压力测试方式,主要用于系统调用量比较小的场景。

  • 请求转发:将分布式环境中多台机器的请求转发到一台机器上

    对于系统调用量比较大的场景,我们有更好的处理办法。其中的一种做法我们称为请求的引流转发,阿里巴巴的系统基本上都是分布式的,通过将多台机器的请求转发到一台机器上,让一台机器承受更大的流量,从而达到压力测试的目的。请求的引流转发方式不仅压测结果非常精准、不会产生脏数据、而且操作起来也非常方便快捷,在阿里巴巴也是用的非常广泛的一种单机压测方式。当然,这种压测方式也有一个前提条件就是系统的调用量需要足够大,如果系统的调用量非常小,即使把所有的流量都引到一台机器,还是无法压测到瓶颈。

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

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

在阿里巴巴,单机压测有一个专门的压测平台。压测平台在前面介绍的 4 种压测方式基础上,构件了一套自动化的压测系统。在这个系统上,可以配置定时任务定期对系统进行压测,也可以在任意想压测的时间点手动触发一次压测。在进行压测的同时,实时探测压测机器的系统负载,一旦系统负载达到预设的阈值即立刻停止压测,同时输出一份压测报告。

因为是在生产环境进行压测,我们必须非常小心,保障压测过程不影响到正常的业务。在单机压测平台上,每个月将进行 5000 次以上的压测,系统发布或者大的变更都将通过单机压测来验证性能是否有变化,通过单机压测获取的单机服务能力值也是容量规划一个非常重要的参考依据。

有了预估的业务访问量,也知道了系统单台机器的服务能力,粗略的要计算需要多少台机器就非常简单了。

最小机器数 = 预估的业务访问量 / 单机能力。

通常情况下,我们会预留少量的 buffer 来防止评估的误差和意外情况。

为什么需要全链路压测?

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

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

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

需要怎么样才能解决这个问题?在 2013 年的双 11 备战过程当中,在很长一段时间内这都是我们面临的一个难题。在中国,学生通常都会有期末考试,为了在期末考试中取得比较好的成绩,老师通常会让学生们在考试前先做几套模拟题。双 11 对我们的系统来说就是一年一度的期末考试,所以我们冒出了这么一个想法:“如果能让双 11 提前发生,让系统提前经历双 11 的模拟考验,这个问题就解决了”。通过对双 11 零点的用户行为进行一次高仿真的模拟,验证整个站点的容量、性能和瓶颈点,同时验证之前进行的容量评估是否合理,不合理的地方再进行适当的微调。

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

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

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

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

为了能够发出每秒 1000w 以上的用户请求,全链路压测构件了一套能够发出超大规模用户请求的流量平台。流量平台由一个控制节点和上千个 worker 节点组成,每一个 worker 节点上都部署了我们自己研发的压测引擎。压测引擎除了需要支持阿里巴巴业务的请求协议,还需要具备非常好的性能,要不然 1000w 的用户请求,我们将无法提供足够多的 worker 节点。上千个压测引擎彼此配合、紧密合作,我们能像控制一台机器一样控制整个压测集群,随心所欲的发出 100w/s 或者 1000w/s 的用户请求。

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

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

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

超限后的流量控制如何做?

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

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

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

当一台机器挂掉以后, 负载均衡会把请求重定向到另外的机器上去,这又无形中给别的机器带来了更多的任务,而这些机器也处于一个饱和的状态,很快也会像第一台机器一样,也无法响应新的请求。就这样,在很短的时间之内,越来越多的机器会停止响应,最终导致整个集群都无法响应。这就使我们常常说的“雪崩效应”。一旦“雪崩”发生,就很难停止。我们必须有一个有效的机制,来监控和控制进入的流量,来防止灾难的发生。

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

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

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

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

阿里高可用的两大法宝

  • 第一步,我们在程序入口给所有的方法都进行埋点;
  • 第二步,我们把这些埋点方法的运行状态,调用关系统计记录下来;
  • 第三步,我们通过从预设好的规则中心接收规则,来根据第二步中统计到的系统状态进行控制。

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

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

阿里高可用的两大法宝

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

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

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

部分转载自他人博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值