目前在中通性能测试主要分为线上和线下压测两种方案,在反复实践过程中我们渐渐发现这两种方案都有着各自不足之处,且为压测工作带来了很多不便。以下就线上和线下压测的不足分析,谈谈中通是如何一步步改进压测方案并解决问题。
在线下压测试过程中,为了减少与真实环境物理资源上的差异,公司采取的是针对 CPU 与内存进行等比缩放的策略,如果是计算密集型应用,线上环境总的 CPU 核数为 80,线下压测环境总 CPU 核数为 8 核,则为 10:1 的线上线下等比缩放策略,如果是 IO(目前只看内存)密集型应用,线上内存总量如果为 80G,线下压测环境内存总量为 8G,也同样是 10:1 的线上线下等比缩放策略。
很明显这种等比缩放策略在高 TPS 目标的压测场景下会失真,TPS 目标越高,则失真越严重,因为我们并不能对网络、中间件、数据库等一系列的因子也同样做出等比缩放。
在线上压测时,多以读接口为主,只有相当少量的写接口会做线上压测,这少量的写接口通常也需要被压应用的开发人员进行代码改造,以避免大量的压测数据对业务数据造成污染。
所以这种线上压测方式无法大范围应用,同时这种对代码硬改造的方式,也增加了压测成本与风险,导致大家通常不愿意面对线上压测,更不用提联合上下游一起进行线上全链路压测了,而这种不敢在线上大量压测的思维,也导致更多压测被放在线下以等比缩放的方式进行,其后果则是压测结果的失真,在 2012 年,某厂正是因为测试环境等比缩放压测,导致网络流量数据失真,引发了线上故障,才促使其下决心走上了线上全链路压测的道路。
因为有上述问题,公司引入了线上全链路压测产品,其特点是使用压测 JavaAgent 探针以字节码方式植入应用,这样业务应用则无须硬编码,就可以自动识别和兼容压测流量,并进行分流,将缓存和存储数据存储到影子区域,实现物理隔离压测数据,避免造成生产数据污染,就技术方案上看,线上全链路压测产品最核心的功能其实就是两点:流量染色与保障数据安全,示意图如下:
在 pradar-web 操作页面的应用管理页,查看是否成功上报:
agent 安装完全成后,在具体实施时,如果压测入口是 http 接口,则在请求头中带上 “User-Agent:PerfomanceTest”,如果入口是 dubbo 接口,则在 AttachementArgs 中带上 “p-pradar-cluster-test:true”,agent 会将这类请求自动识别为压测流量,它会将压测标识向下游应用传递,并将数据分流到应用所配置的影子资源中,例如 redis 的影子 key、影子数据库(表)、rocketmq 上配置的影子 TOPIC 及消费组等等,由此将压测数据与正式数据进行隔离,避免了压测数据对正式业务数据的污染。
缓存 redis 的影子资源,在探针识别为压测流量时,会自动对要写入或者查询的 key 前加上"PT_"前缀来进行数据隔离,而 MQ 的 TOPIC 与消费组影子资源,需要在公司的 ZMS 配置中心,按业务 TOPIC 与消费组名称,去新增出带"PT_"前缀的 TOPIC 与消费组名即可。数据库资源的配置会复杂一些,下面单独说明。
影子库配置如下图所示:
影子表配置如下图所示,都是把业务表名前加上 “PT_” 来表示为影子表,多个表使用逗号分隔:
在线上压测时,有可能会触发到资金扣款或者短信发送等敏感方法,如果大量的压测触发了这类方法,轻则造成骚扰,重则发生严重的资损,类似这样的方法,我们则需要在梳理压测链路时进行识别,并为此类方法加上挡板(Mock),如下图示例,如此当压测探针识别到压测请求 (有压测标) 时,则会执行我们针对此方法所配置的 Mock 代码,如果是正式的业务流量(无压测标),则仍然会执行原来的短信发送方法而不受影响。
做线上全链路压测,很多人担心的一个问题就是,线上生产环境就这么直接压,不怕出问题么,那么除了进行错峰压测以外,中通压测团队为了安全有序的进行线上全链路压测,经过两期接入项目的摸索,已经形成了一整套保障安全压测的实施流程,流程图如下:
全链路压测可以大致分为三个阶段:
1.需求定义与链路梳理阶段;
2.测试环境部署及测试阶段;
3.线上压测及结果产出阶段。
明确压测的具体业务链路与范围边界
明确压测的目的,是达到指定性能指标,还是摸高进行容量规划
具体的性能指标,tps(每秒请求数)/rt(响应时间)/成功率/SA(以 99% 为例,指 99% 的请求响应时间都在设置的 rt 范围之类,也就是 RT 的达标率)
链路梳理是全链路压测最为重要也是最核心的环节,通常这个环节的质量,将影响全链路压测的整体实施效率。接下来详细说一下,链路梳理的目的步骤与需要拿到的关键信息。
首先需要梳理出链路调用大图,刚开始不需要太细,但需要对入口/出口/应用名/数据库/缓存/中间件/资金影响/邮件/短信等,类似这样的一些关键信息能梳理到,因为保密手册的原因,具体的链路图,这里就不放出了,可以用本文最上面的《压测流量链路示意图》进行脑补。
根据上面梳理的梳路大图,进一步明确具体细节,需要收集如下信息:
应用基础信息与部署信息
链路模块 - 指的是这次需求所确定的压测链路
应用名 - 应用名称,在 jvm 中设置时-Dpradar.project.name 的 value 内容
应用负责人 - 一般为应用的主开发人员
运维 - 可以进行 agent 安装包上传与安装,并查看 agent 相关日志的系统运维人员
测试负责人 - 此应用的测试人员
DBA-可以进行数据铺底,影子库表创建,数据库性能监控的 DBA 人员
性能指标 - 本次压测的目标
应用的调用链类型与接口 - 指的是在全链路压测中,本应用在整个链路调用中所经过的接口方法名,以及对应的接口类型,在了解这个信息时,应该要了解清楚这些接口方法的作用与逻辑,以此判断出是否需要对其加挡板 (mock),是否需要进行一些测试数据初始化的准备工作。
启动容器 - 例如 tomcat 或者 jar 方式直接启动
实例数量 - 主要是对测试环境与线上环境的实例实进行统计,需要所有实例全部安装 agent,不然可能导致压测数据流入到正式的数据库表中。
应用入口信息与相关依赖信息
入口 - 压测的入口
数据库 jdbc 连接信息 - 主要是数据库的类型,连接的域名(或者 IP),端口,数据库名称,用户名与密码等相关的信息。
用到的表 - 发起压测后,调用流经到该数据库时,会读哪些表,会写哪些表,数据逻辑是什么,都需要搞清楚,以方便判断怎么造出测试数据,是用影子库方式还是用影子表方式。
文件路径 - 是否会在读写文件的相关信息.
redis 预设值 - 发起压测后,调用流经 redis 的业务与数据逻辑,比如面单的单号是从 redis 中读取的,则我们可以根据压测量,在单号存放的 redis 中预设(铺底)一批测试单号数据,注意对于 redis 中预设测试数据,需要考虑过期时间,另外测试数据的 key 键是在正式的 key 值前加上 PT_来作为影子 key。
mq 的 topic-如果涉及到 mq,则需要建立影子 topic 与影子消费组,方法都是在正式的 topic 与消费组前增加 PT_来作为影子 topic 与影子消费组,需要特别注意的是,影子 topic/影子消费组与正式的 topic/消费组都需要在同一个集群。
es 索引 - 在正式的 es 索引前,加上 PT_作为影子索引.
hbase-正式表前加上 PT_作为影子表.
不良影响 - 在明细信息收集过程中,需要梳理出此应用是否会有产生实际的资金/电话短信邮件/网安数据上报等一系列,有可能因压测而造成的不良影响,针对这些不良影响的调用方法,则需要以加挡板 mock 的方式绕开。
至此,整个链路的业务,技术,数据信息都已经了解得基本清楚了,那么在这个基础上,则可以参考上一节中《 全链路压测部署&配置 》相关的内容,在测试环境将整个全链路压测环境给部署与配置妥当。
### 测试环境调试
全链路压测,向上追述,一般总是能找到一个页面或者 APP 入口,那么必然对应着一个 http 的接口,所以为了表示这个请求是全链路压测的影子请求,需要在 http 头中增加 User-Agent:PerfomanceTest,如果入口就直接是一个 dubbo 入口的话,则在 dubbo 的 Attachment Args 里增加 key:value 为: p-pradar-cluster-test:true
当我们在测试环境观察到压测流量都按我们的预期,落入了相关的影子资源,而没有发生数据落入正式资源的情况后,我们可以在测试环境进行少量数据的压测,如果一切正常,我们就可以开始着手进入线上环境的压测流程了。
提前准备线上必须的影子库表,铺底数据,影子 topic/影子消费组建立等需要 DBA 与运维部门支撑的前期事项。
提前在 pradar-web 操作页面的应用管理页对应用的相关配置进行配置操作。
按照《中通 - 全链路压测上线计划模板.xlsx》编写上线计划,并召集相关人员 (运维,DBA,开发,测试,项目 PM) 评审,提前约定灰度上线,全量上线,试跑压测用例,正式压测的相关时间节点。
将 agent 安装包上传到相关应用的其中一台机器上,如果有预发机,最好是上传到预发机器,然后由开发在发布平台中修改 jvm 配置,配置好 agent 相关的参数,重新启动灰度机器,观察 12 小时以上日志,是否正常。
如果灰度没有问题,则通知运维,将 agent 安装在应用的所有机器,全量重启目标机器。
如果一切正常,则可以使用压测脚本进行线上试跑了,试跑方案应在上线计划中提前规划好:
注:压测试场景配置最好在灰度发布后,就开始进行
1、在 pradar-web 操作页面的系统流程中创建一个流程(一个入口只需要创建一次):
2、在操作页面的 “业务活动” 中创建一个业务活动,并与上面的 “系统流程” 进行关联
3、在 “压测管理”->“压测场景” 中,创建一个压测场景,在业务活动中,将上一步中创建的业务活动增加进去,可以增加多个业务活动,以表明同时压测多个活动的场景,如果有数据文件且数据不可以重复使用的情况,可以选择多个 IP 后,对此 csv 数据文件勾选 “拆分” 操作,最后还需要关注的是正式压测,需要使用 “阶梯递增” 模式,则您的 Jmeter 脚本中需要以"bzm-Concurrency Thread Group"方式创建线程组。
确认了压测时间与相关人员后,编写压测计划,并通知到相关人员按计划执行,同时要特别注意压测入口域名是否受到 CDN 与防火墙的流量限制,如果有,需要提前找运维与网络的支撑人员将压力机 IP 加入白名单。
一切准备就绪,则按计划执行压测即可,在 “压测场景” 中点 “启动”,正式发起压测。
以某场景为例得到如下压测报告:
除了一般性能测试都要进行的监控以外,进行全链路线上压测试时,最大的区别是我们大量使用了影子数据库表,影子数据库表用于与正式数据库表进行测试数据的隔离,且压测数据我们都会加上识别标识,比如 PT 开头的订单号都是压测数据,但因为各种原因,大量的压测数据可能会导致部份或者全部压测数据被错误的写入了正式数据库表,从而污染了真实环境的数据,导致各种生产故障,因此有必要实时的检测是否有测试数据被错误的写入了正式数据库表,以便及时的停止压测行为,并快速对进入正式库的错误数据进行清洗纠正,将损失降到最低。为此,我们自己基于对数据库 binlog 的监听,设计了一套能实时监控压测数据对生产数据造成影响的工具,原理图如下:
使用压测探针方式进行线上压测以来,我们已经在订单,运单,面单等多个业务共 62 个应用中进行了接入,成功支持了双 11&618 大促与淘宝&拼多多等大流量联合线上压测的场景,虽然初步能解决原来压测中存在的问题,但也引入了一些新的问题。
先看看某大厂 BU 进行全链路线上压测的简化版组织及工作模式架构图:
中通全链路线上压测组织与工作模式图:
全链路压测系统接入几乎牵扯到整个产研团队的各个方面,需要开发、测试、运维及供应商等团队充分配合协同工作。
图一中某大厂由于订单全链路压测属于公司级重点项目,由上至下的推动相关系统改造和统一协调资源,各项目由开发负责人挂帅,开发、测试、运维相互配合,性能团队属于支撑团队,负责压测方案评审、工具支持、压测问题记录与答疑。
图二中我们的模式,全链路压测属于部门级项目,由性能测试团队负责主导,对接各方推动接入工作,其他相关方属于配合工作人员,性能测试团队需要协调各方资源,工作难度较高。
手工操作过多,自动化程度太低,比如探针的版本控制与部署,施压机的自动创建与分配等。
流程推进线下化,没有形成统一管理的配置项、检查项、评审等流程在线化推进。
测试脚本与测试数据在线化统一管理及可复用程度底。基本靠压测人员自行维护。
压测所积累的结果数据,无法在线形成压测基线自动化对比,无法达成压测结果在时间线上的可视化统计与分析。
中通通过引入全链路压测,的确解决了原来压测环境等比缩放压测的失真问题,但是,在面对整个在订单,运单,面单等多个业务共 62 个应用的压测,单从上下游数据层面交互就是一项复杂的工作,另外还需要各个环节的人员协作等、工作量及复杂度是可想而知的。因此,此项工程并非一天两天能全部解决的,路漫漫其修远兮,后面我们还将通过发起性能专项创新活动,将公司性能测试总体价值推向更高阶的层次。
https://testerhome.com/topics/31821
https://testerhome.com/topics/31820