写点什么

深度解析全链路压测实施过程

  • 2022 年 8 月 30 日
    北京
  • 本文字数:3406 字

    阅读完需:约 11 分钟

深度解析全链路压测实施过程

在开始全链路压测前,还要梳理核心链路、准备测试数据、改造系统并进行流量染色。对一些老旧系统实施改造并不容易,往往涉及各种复杂的业务集成,改造成本比较高。

1、核心链路梳理

第一步是梳理。梳理系统中的业务场景,并找到支撑和实现业务场景的信息流的链路,这些信息有助于我们知道要测的是什么一般来说,业务系统的场景有很多,用户当然不会对每个场景都平均地进行访问,所以,做全链路压测时,用户集中使用的场景对应的服务之间进行调用的链路通常是我们要梳理的核心链路。这个梳理过程并不难,从调用入口着手找到它需要调用的其他服务接口,只要明确了这些调用关系,就能得到技术上的核心链路。通常还需要和业务分析师一起对核心链路进行二次确认,以避免测试过程中出现偏差。这一步梳理过程很重要。


第二步是记录。将确定好的核心链路中的服务调用关系记录下来,同时记录下分支业务等信息,标注出需要参与性能测试的场景,而不需要参与测试的场景也需要做出标注,方便后续工作的跟进。随着业务系统不断演进改变,核心链路相关的文档也需要及时更新。


第三步是隔离。对核心链路中不能参与性能测试的部分要进行隔离,例如第三方的支付接口、短信网关接口、物流运输系统等,这些系统的性能需要第三方自己去保证。在进行隔离时,可以考虑把第三方系统替换成按照接口契约 Mock 出的系统。

2、准备测试的数据

在产品环境下的全链路压测通常使用的是线上的真实数据,线上数据的多样性可以让测试涵盖系统中更多的被测场景和代码路径。当然,在使用真实数据时需要对它们做脱敏处理。线上数据的获取方式主要如下。

  • 抽取系统日志,还原用户的访问请求并在系统中进行回放。高峰时段日志更具有测试代表性。

  • 用 SQL 脚本从产品环境下的数据库抽取数据并进行改造,改造后的数据可以作为压测数据。线上数据包含各种用户敏感信息,如身份证号、手机号、家庭住址等,测试前要对这些数据进行脱敏处理(对数据进行批量替换、增加随机数等)。除此之外,线上数据还包含临时 Token 等信息,需要将其替换成长时间有效的 Token,才能被系统反复使用和执行。


全链路压测中,性能铺底数据的量级应该和产品环境下的数据量级保持一致,还要结合线上业务增长率,提前准备半年或者一年的数据量。如果是新业务上线,可能暂时没有线上数据作为参考,那么就需要人工预测铺底数据的量级了。性能测试数据需要定期清理,一般我们采用编写脚本的方式进行自动化清理。长时间不清理的话,测试结果是会受影响的。

3、改造系统并进行流量染色

在测试环境中做性能测试时,自然不需要担心测试过程对产品环境的用户造成影响,也不需要考虑测试数据的隔离。而在产品环境中,必须对测试数据进行隔离,否则会污染线上数据,这一点我们反复提过很多次了。如何实现测试数据不影响产品环境的数据呢?需要通过对性能测试请求增加染色标识来区分测试请求和真实请求。


对于微服务系统常用的 HTTP 调用接口来说,在 HTTP 请求的 Header 中添加特殊标记,以提示 HTTP 服务器这是测试请求,这种方式是个不错的选择,不影响请求数据,侵入性也是极小的。当使用其他协议发送请求给微服务系统时,也可以使用这一思路。


HTTP 服务器端在接收到包含染色标识的请求后,会立刻把请求转发给业务处理模块,这些模块涉及缓存层、线程池、数据库、日志等环节,要对这些模块做相应改动,来保证带有测试标记的请求和产品环境数据分离开。在处理过程中要防止测试标记丢失,因为标记一旦丢失,后续处理模块就无法区分数据的实际身份到底是测试数据还是真实用户数据,这将直接影响到产品环境下的用户使用体验。


全链路压测改造的系统涉及 HTTP 服务器、应用程序的代码、消息队列、缓存层、数据库等环节,最终把测试数据写入影子表、影子日志目录。在改造过程中,首先要识别出读接口和写接口。读接口不涉及测试数据的隔离操作,隔离主要是针对写接口的。改造的内容主要包括以下几方面。

  • 线程池。以 Java 语言为例,当测试请求进入线程池后,要把测试标记写入线程的 ThreadLocal 变量中,方便测试标识跟随线程传递到下个处理环节。

  • 缓存层。缓存层存储了大量用户经常访问的数据,可以加快用户访问速度。测试过程中产生的数据可能会把用户正在使用的缓存数据冲掉,因此我们有必要隔离出缓存服务器并把测试数据写进去,从物理上将测试数据和真实业务数据分离开。

  • 影子库和影子表。对数据库的改造有两种方案—影子表和影子库,具体选择使用哪一种则应根据实际情况来。

影子表创建在产品数据库中,复制产品数据库对应表的结构,同时保证同样数量级的初始数据。一般我们在影子表名称后加特殊后缀以进行区分。创建影子表不但成本较低,也不用单独购买数据库的使用授权。然而由于影子表和业务表共享内存等资源,这又会导致测试过程中可能对产品环境产生一定影响。


影子库,是我们创建的一个独立的、和产品环境相同的数据库。因为它是独立的,所以在测试过程中对产品环境数据库的影响很小。也正因为独立,它需要购买数据库使用权,并且搭建对应的硬件基础设施,导致投入成本较高。

  • 消息队列。当测试数据进入消息队列时,会出现两种可能:一是根据业务情况做丢弃处理;二是带着测试标记传递到其他模块进行处理。

  • 日志模块。当测试日志和真实用户日志混在一起时,分析和排查起来相当麻烦,我们通过建立影子日志目录对日志模块进行改造,方便区分测试日志数据和真实日志数据。

  • 搜索引擎等模块。搜索引擎或者 BI(Business Intelligence,商业智能)分析系统,会读取产品数据库,扫描和抽取数据。在这个过程中,要防止影子表、影子库的数据被扫描到。


系统改造过程中,任何一个环节的遗漏都有可能造成测试标记丢失,为了避免测试过程中出现标识遗漏现象,对测试数据的隔离效果也要进行验证。正式开始全链路测试前,先在测试环境进行全面的演练测试,确保性能测试过程符合设计预期。验证的过程分为 4 步。

  1. 在测试环境验证单次请求:把改造完的系统部署在测试环境,发送单次请求验证测试标记的流转是否符合预期,以及写入数据是否进入了影子表、影子日志目录。

  2. 在测试环境验证多线程请求:从产品环境抽取数据并做脱敏处理,把这些数据用在测试环境中,使用多线程并发测试。线上数据的多样性可以让测试覆盖更多的代码路径。

  3. 在产品环境验证单次请求:由于线上环境和测试环境存在配置等差异,因此在产品环境测试时,也需要先发送单次请求进行验证,确保线上各个环节对测试数据做到准确隔离。

  4. 在产品环境验证多线程请求:使用线上脱敏后的数据在产品环境做性能测试。测试前要对所有数据进行备份,确保测试出现问题时能够及时恢复数据。

4、测试过程和测试监控

在产品环境下做全链路压测时,尽管我们选择的是业务低峰时段,但在整个压测过程中仍需随时关注系统的各项指标,避免影响线上用户的正常使用。执行时我们通常选择平滑加压的测试方式,而不是一开始就把测试请求全部发送出去,这是为了避免系统被压垮。在接下来的测试过程中,一旦系统出现异常行为,如响应过慢或者错误率超过预期标准,就要及时停止增加访问流量,并对异常问题进行排除。


在全链路压测过程中,需要实时收集系统服务器、数据库、接口业务处理情况等各种信息,来作为检测系统是否正常的依据。监控的内容除了常见的服务器资源使用情况,还包括系统中各微服务接口响应结果的正确率、响应时间、每秒请求数量等信息。从业务处理的维度对系统进行监控,也可以反映系统的处理能力,包括每秒创建订单数、每秒交易次数、下单失败率等监控指标,监控的内容还会包括系统日志中的异常信息以及消息队列等中间件的实时处理速度等。

5、异常处理方案的验证

全链路压测可以检验系统的限流、降级措施是否正常。微服务系统通常会对超过预期的流量做特殊的处理,比如限制流量或是按顺序分别处理,来确保绝大多数用户的正常使用。还有一种方式是降级,降级是指当遭遇流量高峰时,系统根据设定自动停止一些不重要的服务,保证核心业务的正常运转。待系统流量恢复正常后,对其他业务进行重新启动。


测试环境下的性能测试其实在测试整体工作中占有很大比例,这是因为在测试环境中,我们对机器的使用、部署等有充足权限,方便去定位一些性能缺陷。越早发现缺陷,修复该缺陷的成本越低。因此测试环境下的性能测试是必不可少的。测试环境下的性能测试可以无风险地发现程序级问题,而产品环境下的性能测试是低风险精确评估生产系统容量,两者互为补充。不做测试环境下的性能测试,可能会导致系统在产品环境中频繁出现性能故障。


发布于: 2022 年 08 月 30 日阅读数: 41
用户头像

InfoQ签约作者 2018.11.30 加入

热爱生活,收藏美好,专注技术,持续成长

评论

发布
暂无评论
深度解析全链路压测实施过程_全链路压测_穿过生命散发芬芳_InfoQ写作社区