07 | 工具进化:如何实现一个分布式压测平台

你好,我是吴骏龙。工欲善其事必先利其器,今天我将与你分享如何自己实现一个分布式压测平台。

现在只要是规模大一些的互联网公司,都在不遗余力地开发自己的压测平台,比如京东美团阿里360。可能你会问,市面上已经有无数的开源压测工具和平台,比如JMeter、Locust、nGrinder、Gatling等,为什么要自己做呢?我在和一些大厂的同行交流经验时,发现对于常见开源压测工具的诟病不外乎有以下几点。

从开源压测工具和平台的这些缺点中,我们可以看出,对于企业来说,自研压测平台就是要满足以下三点需求:

1. 平台化: 企业需要一个平台化的压测工具,每个团队都可以在这个平台上协作,而开源工具大多是C/S类型( 客户端/服务器体系结构),缺乏平台化支持。

2. 标准化: 企业需要一个统一的标准化压测平台,最好能够和公司的审批流程、管理平台等集成,而开源工具在这方面的扩展性一般不强。

3. 控制成本: 企业需要控制压测平台的维护成本,对于规模大的公司,自研优于使用开源。虽然开源压测工具由社区维护,但反馈较慢,自己维护的成本又比较高,不如重写一个或者二次开发。

在这一讲,我会介绍一套由我设计的基于JMeter的分布式压测平台实现方案,这套方案也兼顾了开源工具的一些成熟功能,目前已经在阿里本地生活团队使用了超过4年,能够支撑近百万压测并发量,累计输出了近4000亿次请求量,管理近600台压测机,依然没有出现明显瓶颈。这些成绩到底是怎么做到的,我们来一探究竟吧。

架构设计思路

首先,实现一个分布式压测平台,要能解决上面提到的绝大部分问题,需要实现的功能可以细化为以下几个方面:

  • 用例管理: 用户建立测试用例,包含脚本文件、数据文件和插件,平台进行分类管理并持久化。
  • 压测执行: 一键触发测试用例,可指定各种运行参数,可以指定多台压测机分布式执行,可以批量执行多个测试用例,压测过程中能够动态调节压测量。
  • 实时结果(热数据): 压测过程中,实时展示响应时间、吞吐量、错误率等概要数据。由于这些数据都是在压测时需要高频关注的,我们将其称之为“热数据”。
  • 压测结果(冷数据): 在压测结束后,展示平均响应时间、平均吞吐量,90/95/99线等更详尽的数据。这部分数据主要是供压测后的分析工作使用,不需要实时获取,因此被称之为“冷数据”。
  • 压测机管理: 平台能够与压测机进行交互,调度压测机完成压测执行工作。
  • 安全保障: 平台应具备一定的监控机制,对压测过程中的一些异常情况进行干预。

我们建设分布式压测平台的理念是“取其精华去其糟粕”,尽可能复用已有开源工具的成熟功能,因为这部分功能相对稳定,不需要重复造轮子;对开源工具不成熟的功能应当规避,在压测平台中进行实现;对开源工具不具备的功能,则完全在压测平台中实现。

下图是分布式压测平台的顶层设计图,它是典型的Java Web项目,平台本身不执行测试只做调度,避免成为施压的瓶颈,后台均使用JMeter执行测试。平台会对挂载的压测机进行心跳检测,确保压测机是可用的。用例和数据文件可以存储在服务器本地,或者采用MinIO进行高可用的文件对象存储。压测期间产生的冷数据持久化至数据库,热数据持久化至时序数据库(InfluxDB)并定期清理。平台允许挂载外部监控模块,对压测过程进行干预。

这里,你需要注意,在使用JMeter进行压测时,如果并发量比较大,单机的资源配置可能无法支撑,这时需要联合多机进行分布式压测,然而JMeter自身的分布式压测功能是有一定缺陷的:

  • JMeter的分布式执行和单机执行方式的差异较大,需要做很多额外配置,由此产生大量运维工作。
  • JMeter分布式执行模式,master节点通常不参与压测,而是收集slave节点的压测信息,这会造成一定程度上的资源浪费。
  • JMeter分布式执行模式,slave节点会将每个请求打点都实时回传给master节点,造成大量的带宽消耗。

这时候怎么办呢?上面我提到过,对开源工具不成熟的功能应当规避,因此,我们可以在每台压测机中植入一个Agent,它能够与压测平台服务器通过长连接的方式建立通信,这样平台就可以直接对压测机进行调度。这种方案相当于我们在平台层重新实现了JMeter的分布式调度功能,两者的实现对比见下表。

这个方案也一并实现了压测过程中的冷热数据分离,冷数据在测试完成后才会传输,如果不需要压测端数据,甚至可以配置不存储冷数据,因此该方案的扩展性是非常友好的,理论上支持的TPS没有上限。

主要功能实现方案和原理

说完了需要实现的功能和架构设计思路,相信你对我们要实现的压测平台已经有了初步认识,下面我就从平台的6大功能实现方案和原理进行展开,沿着基础功能到高阶功能的顺序进行讲解,展开的粒度大约控制在让你稍加思考就能上手实现的程度,你可以选择擅长的编程语言及前后端框架去实现具体功能。

如果你希望能更直观地看到整个平台的功能全貌,我也制作了一个预览视频,在这一讲的最后我会提供给你。

1.如何实现测试状态流转

测试状态流转是压测平台管理测试工作的核心,所以我放在第一个讲。和人类的生老病死一样,每一轮成功的测试工作会经历一个完整的生命周期,可以描绘成下面这条主线。

其中,我将配置、触发、运行、收集、清理定义为五大内部行为(平台内部逻辑管控),这五大内部行为都会改变测试的状态;同时,我们还会允许一些外部行为去干预测试工作,比如在运行过程中需要人为停止测试,外挂的监控组件判断异常后主动熔断测试等,这些外部行为也会改变测试的状态。你可以通过下面的表格,理解各个行为对测试状态的影响,以及对应的后续行为是什么。

将这些状态变换的触发条件和转换过程绘制成状态流转图,就是下面这个样子。

说白了,压测平台对测试状态的管理,就是通过代码实现出这张图的所有逻辑。其中的关键是,无论测试流程出现何种分支(正常或异常),最后都要能形成闭环(即起点一定最终要达到终点),这对系统的健壮性非常重要,因为如果测试状态卡在任何中间状态,本质都是平台对其失去了管理,测试的信息都丢失了。

2.如何获取和展示实时数据(热数据)

上面我讲到了实现测试状态流转的整体思路,其中在“运行中”状态下,我们需要获取压测时的实时数据,以便实时观察压测情况。

我们这套分布式压测平台实现方案,是基于JMeter的,但遗憾的是,JMeter本身并不提供图形化的实时数据展示功能,以往我们只能通过输出日志看到一些粗略的信息。在压测平台中,我们就对实时数据展示功能进行了实现,主要原理是通过JMeter的Backend Listener将测试结果实时发往InfluxDB,同时平台向InfluxDB轮询查询数据,得到实时曲线并展示给用户。

当然,你也可以直接基于流行的开源数据可视化系统Grafana进行数据展示。

另外,补充一句,我在2017年为JMeter贡献了基于UDP协议与InfluxDB传输数据的Backend Listener,比起当时官方支持的HTTP协议,传输效率更高,被列为JMeter 3.3的核心改进项,如果你也想使用这个UDP协议的Backend Listener的话,请确保JMeter版本 ≥ 3.3,欢迎你尝试。

3.如何处理结果数据(冷数据)

实时数据要讲究快,能实时观察压测结果,比如,我们只要看到响应时间和错误率就可以基本了解压测当时的状态了。但对结果数据要更讲究全,目的是在压测结束后对压测结果做详细分析时,能精细到看到每个报错信息是什么。

由于压测平台自己实现了分布式压测模式,因此在拿到每台压测机的结果文件后,也需要自行对这些结果文件的内容进行合并和解析,并持久化记录下来。这里所谓的结果文件其实就是压测生成的JTL文件,我们先来看下JTL文件的一个片段。

timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,URL,Latency,IdleTime,Connect
1617696530005,81,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,78,0,43
1617696530088,32,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,32,0,0
1617696530120,32,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,32,0,0
1617696530152,32,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,32,0,0
1617696530184,31,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,31,0,0
1617696530216,31,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,31,0,0
1617696530248,31,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,31,0,0
1617696530280,31,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,31,0,0
1617696530312,31,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,31,0,0
1617696530343,32,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,31,0,0
1617696530375,32,HTTP请求,200,OK,线程组 1-1,text,true,,2497,118,1,1,http://www.baidu.com/,32,0,0

JTL文件的特点很鲜明,可以看到,相对应每一行的单条结果数据的大小非常小(大约只有100多个字节),但总量很大(上面的例子只是片段,实际可能有几万到几百万条)。如果我们只是简单的将所有数据存储起来,将会占用大量的存储空间,因此结果数据需要做预聚合再存入。

预聚合是怎么做的呢?下面代码展示了聚合存储的数据结构,核心是以label(JTL中的label)作大分类,维度(errorMsg、errorCode等)作小分类,以时间作为聚合标准,interval固定,固定聚合为60个点,从而保证存储大小不会过大。

{
    "label": "upload", -- 大分类,比如这条记录只针对upload label
    "totalCount": 428,
    "totalErrorCount": 12,
    "errorMsg": [ -- 维度字段,作小分类
        {
            "msg": "io.exception",
            "count": 12
        },... -- 固定聚合成60个点
    ],
    "errorCode": [
        {
            "code": "404",
            "count": 12
        },...
    ],
    "count": [
        12, …, 15
    ],
    "error": [
        12, …, 15
    ],
    "rt": [
        12, …, 15
    ],
    "minRt": [
        12, …, 15
    ],
    "maxRt": [
        12, …, 15
    ]
}

结果数据的这种存储方式,既保证了不会占用太大的存储空间,又能够汇总出丰富全面的数据。

4.如何进行吞吐量限制与动态调节

测试状态流转、冷热数据的获取和处理是压测平台最基本的功能,下面我来介绍一些更高阶的功能,先从吞吐量控制与动态调节开始吧。在压测时,“控量”是非常重要的,JMeter是根据线程数大小来控制压力强弱的,但我们制定的压测目标中的指标往往是吞吐量(QPS/TPS),这就给测试人员带来了不便之处,必须一边调整线程数,一边观察QPS/TPS达到什么量级了。

为了解决这个问题,JMeter提供了吞吐量控制器的插件,我们可以通过设定吞吐量上限来限制QPS/TPS,达到控量的效果。

上面的做法能够确保将吞吐量控制在一个固定值上,但这样还远远不够,实际工作中我们希望在每次压测执行时能够随时调节吞吐量,比如,在某个压力下服务容量没有问题,我们希望在不停止压测的情况下,再加一些压力,这样的功能该如何实现呢?

我提供的方案也很简单,依然是基于吞吐量控制器,基本的实现原理是将吞吐量限制值设为占位符(如下图中的${__P(throughput, 99999999)},throughput就是占位符),利用JMeter的BeanShell功能,通过执行外部命令的方式,在运行时注入具体值,达到动态调节吞吐量的目的。

上面提到的外部命令具体为:

java -jar <jmeter_path>/lib/bshclient.jar localhost 9000 update.bsh <qps>

其中,update.bsh文件的内容为:

import org.apache.jmeter.util.JMeterUtils;

getprop(p){ // get a JMeter property
    return JMeterUtils.getPropDefault(p,"");
}

setprop(p,v){ // set a JMeter property
    print("Setting property '"+p+"' to '"+v+"'.");
    JMeterUtils.getJMeterProperties().setProperty(p, v);
}

setprop("throughput", args[0]);

压测平台将上述这些工作统一封装后提供出接口,前端界面只要留出输入框供用户填写吞吐量的参数,就可以方便的使用了。

5.如何实现配置集功能

我们再来聊一个和压测运行相关的重要功能,称之为“配置集”。这个功能其实当初并不在平台设计的考虑范围内,但随着全链路压测规模的日益壮大,需要同时执行的用例数量越来越多,每次执行时都得一个一个去触发,手忙脚乱,有了这个痛点,引发了我们对配置集功能的探索。

配置集功能的本质是“批量运行多个测试用例”,如下图所示,用户只需提前在配置集中添加需要执行的测试用例,以及每个执行轮次的配置信息,比如线程数、持续时间等。配置集设定完成后,选择某个轮次,就能基于相应的配置一键触发所有测试用例。

从实现的角度来讲,配置集是映射多个用例的数据结构,而刚我们提到的“轮次”的概念,是指对同一个配置集设定多轮不同的配置项,每个配置项还是作用在测试用例上,目的是进一步提高可复用性。简而言之,记住这个公式:“配置集 1:N 测试用例;测试用例 1:N 轮次配置”,即一个配置集对应多个测试用例,一个测试用例对应多个轮次配置。再直观一些,你可以直接通过下面的代码理解这个逻辑。

{
    "_id" : ObjectId("603c7f8f587ca226d257b144"),
    "testPlanName" : "addTestPlan",
    "testPlanUnitList" : [ -- 一个配置集对应多个测试用例
    {
        "testcaseId" : "5fc4dd4ee9d7d7b19d0f5152",
        ……
        "testRoundList" : [ -- 一个测试用例对应多个轮次配置
        {
           "threadCount" : 1,
           "duration" : NumberLong(60),
           "rampUp" : 0,
           "detailLog" : true,
           "realTimeLog" : true,
           "throughput" : 100,
           "name" : "配置1",
           "qpsStep" : 0
       }, ……
       ]
    }
    ],
 ……
}

由于在配置集中同时管理着多个用例的所有信息,因此还可以实现一些高级操作,比如:某个用例先执行一段时间后,其他用例再启动,其本质就是单独先触发一个用例,等待固定时间后再触发其余用例;或是,运行时临时改变其中几个用例的QPS上限,其他用例保持不变,其本质就是对单个用例进行吞吐量调节,等等。

6. 监控模块

我已经介绍了很多关于压测运行和压测数据的功能模块,最后我们来学习一下监控模块,它同样也是压测平台非常重要的组成部分,也是几乎所有开源压测工具都缺乏的功能模块。监控模块可以分为两类,分别是内部监控模块和外部监控模块。

内部监控模块主要针对压测平台自身运行过程进行监控和干预,观察压测是否处于正常进行中,如果遇到异常情况,如线程异常终止、没有持续的测试数据流出、磁盘打满等,则立刻终止测试,反馈异常结果并记录日志供排查。

内部监控模块实现起来也很简单,在触发压测后,我们也同时启动一个任务对使用的压测机进行监控,监控的内容可以是磁盘使用量、压测数据流的状态等等,如果识别到异常,则触发相应的异常逻辑即可。

第二类监控为外部监控模块,主要用来对接外部监控系统,这个模块很重要,除了方便观察系统指标以外,其最关键的作用是能够反向干预压测工作,协助用户规避风险,尤其是针对线上压测这类高风险工作。比如,当监控到服务端的错误率达到一定阈值时,立刻停止当次测试。

外部监控模块的实现,需要与外部监控系统提供的接口对接,如果有些监控系统自带报警功能,那么就更好了,压测平台在获取到报警信息后可以立刻停止测试。

以对接Grafana监控为例,最简单的方式莫过于采用Webhook的方式,我们只需要指定一个接口并配置到Grafana中,在监控告警事件发生时,Grafana就会回调这个接口,触发相应的停止测试的动作。当然,也可以触发其他动作,这取决于接口的逻辑。在Grafana使用手册中提供了详细的对接案例,你可以进一步阅读,加深理解。

总结

工欲善其事必先利其器,压测平台作为容量保障的工具枢纽,其地位不言而喻。一个扩展性好、设计健壮、体验优秀的压测平台,能够对容量保障工作带来巨大帮助。

这一讲中,我介绍了一个基于JMeter的分布式压测平台的实现方案,它解决了企业对于压测工具的三个重要诉求:平台化、标准化和控制成本。如果你的团队已经习惯于使用流行的JMeter进行压测,那么上手这个平台几乎是没有什么成本的,因为它100%兼容JMeter。

平台的主要功能可以分为几大部分去看,首先是测试状态,我们明确了测试行为和测试状态之间的流转关系,确保无论测试过程是正常执行还是异常终止,整个流程都能闭环完结。

其次是测试数据,我们将数据分为热数据和冷数据,分别对应实时数据和结果数据,并采用了完全不同的思路去实现,确保各自的特点能够充分发挥。

接下来,我们聊到了测试运行过程中的两个重要功能,吞吐量动态调节和配置集。其中,吞吐量动态调节利用了JMeter BeanShell的动态传参功能,我们只需要暴露吞吐量作为参数即可;而配置集则是平台对多测试用例运行的一种实现,能够方便我们批量执行大量测试用例。

最后,监控模块是压测工作安全性的重要保证,内部监控模块对压测本身的状态进行检查,如有异常及时反馈;外部监控模块则是对接外部监控系统,在服务出现异常时主动终止测试。

通过今天的学习,希望能够让你了解分布式压测平台实现的重点和难点,也期待你能够创造更多方便友好的功能,为容量保障工作的降本提效贡献一份力。

课后讨论

这里,我给出一个分布式压测平台的预览视频,包含这一讲提到的所有功能,它可以作为你的实现蓝本。如果观看了视频后,你有了什么新的思路或启发,欢迎分享给我,我们共同探讨。

精选留言

  • Hale

    2023-05-26 08:24:56

    老师好,请问,使用agent是怎么判断jemter压测结束各个状态的?这块不理解
    作者回复

    你好,我们可以回顾一下文中的状态变换表格和状态机,其中每个状态都有成功的条件和失败的条件,具体状态是保存在数据库中的,我们可以通过轮询这一状态,根据结果决定是否执行后续步骤。整个逻辑都是状态机管理的,Agent只负责执行指令。

    举个例子,当用户触发一次压测,系统会同时建立三个任务:配置、执行和运行。配置任务在成功完成后会将状态置为BOOTED,失败则置为BOOTERROR。与此同时,执行任务在不断轮询状态,一旦轮询到状态为BOOTED,立刻执行触发逻辑,如果轮询到状态为BOOTERROR,则终止,并取消后续运行任务。运行任务的原理也是一样的。最后,有一个收集任务做兜底清理工作。

    值得注意的是,平台的视角是压测的状态管理,并非局限于JMeter的工作状态。

    2023-05-27 10:27:44

  • 天启

    2023-02-20 11:22:04

    老师我又有问题啦,就是如果在每个压测节点部署一个压测的agent程序,假设我理解为这个是个javaweb应用程序吧,这样就相当于压测任务开始的时候一个虚拟机上有2个java进程一个是这个javaweb程序,一个是jmeter的java进程,那么会不会存在压测的时候这个jmeter进程挤占这个javaweb程序的资源,导致这个代理程序崩溃,这种有什么好办法吗,还是说2个进程都搞成容器化,可以资源独立
    作者回复

    你好,这个agent是一个用Java编写的轻量级Lib,使用Netty与服务器进行通信,自身持有的资源很少。此外,agent所做的工作是低频的,例如:每轮测试中的同一类文件只需要传输一次,各个状态变换时下发的指令也是有限的。唯一比较消耗资源的是结果文件的聚合(消耗CPU)和回传(消耗带宽),但这一操作是在压测结束后异步进行的,因此资源消耗是错时的。

    另外,agent的JVM进程和JMeter的JVM进程是隔离的,两者都有自己的堆大小和栈大小控制,只要相加不超过总的内存大小,一般不会互相影响。

    2023-02-26 11:37:06

  • 天启

    2023-02-02 10:05:12

    老师问下,最近在使用阿里pts工具的时候,发现pts有个叫采样日志率的概念,可以看到压测过程中某些请求的详细返回信息请求信息,感觉对压测问题分析挺有用的,但是参考jmeter的实现看了一圈,我想到相对2种实现方式:1.修改jmeter的properties文件,让jtl文件中展示更多的信息展示,但是这个有很多的缺点需要消耗压测节点大量的磁盘空间,且这个结果是在压测结束后才能进行处理2.第二种方式是自己写一个backendListener插件,在钩子函数中发送sampleresult,但是这个有个难点,就是样本总数在运行时无法确定,不太好实现日志采样率。所以想问下老师这块你们的压测平台有去实现吗,想借鉴下思路
    作者回复

    你好,你的问题关注的是如何获取压测流量的响应信息,我们的压测平台是通过对接JMeter的“查看结果树”控件来实现的,激活“Save Response Data”,同时勾选“仅错误日志”(一般来说,只有排障时才需要关注详细的响应信息),生成的结果文件以固定的文件名保存,压测平台的服务器会在压测后统一回传至文件存储组件供下载,默认保存7天。当然,由于查看结果树的结果文件是以流的形式实时构建的,因此我们也提供了实时查看的功能,压测平台服务器提供了后端接口,将文件内容实时读取出来,前端得到结果后展示在页面上。

    查看结果树本身提供了设置响应数据最大展示大小,以及最大文档大小等参数,基于这些考虑,我们并不需要以抽样的方式获得数据。

    2023-02-04 15:21:33

  • 天启

    2022-09-21 21:17:31

    老师你好,我想问下通过部署agent的方式来规避master-salve的痛点的话,压测机的启动方式是以jmeter-server方式的吗,还是说是用agent,动态的进行命令行方式jmeter -n xxxx动态启动压测?
    作者回复

    你好,启动方式是后者。我们完全放弃了JMeter的分布式执行策略,因此也就不再使用jmeter-server的启动方式,所有JMeter节点都视为是Master由平台统一调度。

    2022-09-22 19:03:28

  • 菜蜗牛

    2022-05-25 14:20:30

    老师,您好, 请问您的压测平台是否是开源的呢?是的话,是否可以贴一下源码地址
    作者回复

    你好,我确实早有开源的计划,但因为一些限制暂时无法达成,一旦能够开源,我会及时更新,感谢你的关注

    2022-05-30 19:30:00

  • 追风筝的人

    2022-05-17 09:33:43

    老师 你知道客户端使用mc 工具, 服务端是3个节点的minio集群 怎样做对服务端的上传 下载 性能测试? MC这个工具怎么指定并发数
    作者回复

    你好,mc工具我不太熟悉,无法提供专业的指导,非常抱歉

    2022-05-22 09:22:16

  • 林林总总0107

    2021-11-18 18:00:33

    老师,想问下关于线程数与TPS/QPS动态设置的时候,这里面的关系应该是怎样的?比如,执行java -jar /lib/bshclient.jar localhost 9000 update.bsh <qps>,这里面只有调整QPS/TPS,但是没有线程数的调整,是不是说只需要调整<qps>,不管线程数的调整?我看到配置集功能里面的用例也有总线程数的参数项,具体执行测试的时候这个值应该怎么去调整呢
    作者回复

    你好,如果需要调节QPS,线程数一般适当设大点就行了(线程数是固定值),如果线程数设的太小,达不到目标QPS,那么调节也就没意义了。当然,也不要把线程数设的太夸张,一方面压测资源不一定够,另一方面JMeter是通过间隔抛弃请求达到控制QPS的效果的,线程数太大可能会造成抖动。

    2021-11-18 23:41:14

  • ask001

    2021-07-19 16:17:48

    谢谢老师之前问题的答复!老师我现在还有个疑问是看jmeter自带的InfluxdbBackendListenerClient逻辑是:BackendListener会把SampleResult丢到BlockingQueue中,BackendListener也会起一个线程从BlockingQueue中取SampleResult丢给BackendListenerClient处理。InfluxdbBackendListenerClient处理SampleResult的逻辑是最终把SampleResult加到DescriptiveStatistics中,InfluxdbBackendListenerClient会起一个定时线程池,定时利用DescriptiveStatistics先计算一下在定时时间间隔段(默认值5秒)采样到的SampleResult的统计值(比如平均响应时间、总的sample、5秒内95线等)发给influxdb。所以InfluxdbBackendListenerClient其实入influxdb的值是在定时间隔段内计算后的值。老师想问下如果是多节点每个节点都是上报给influxdb,如果用jmeter自带的InfluxdbBackendListenerClient是不是不合适?还是说自己写一个InfluxdbBackendListenerClient,把原始的采样结果入influxdb,这样方便influxdb 取数据加工(根据具体指标进行求和或求平均值等),如果是原始的采样结果入influxdb我觉得jmeter每次采样数据发influxdb会是瓶颈,影响压力机资源,同时因为用的社区版influxdb,TPS大的化influxdb也可能会是瓶颈?
    作者回复

    为你的认真细致点赞!我说下我个人的理解。

    对于实时数据,一般来说我们其实只需要观察一个宏观的指标概要,判断压测时的大致状况,有无风险等。而对于非实时数据,则需要计算出精确的指标(如99线等),因为我们要输出结论供详细分析和其他决策参考(限流等)。

    这是压测平台将数据进行冷热分离最原始的初衷,越精确的结果,必然会带来越昂贵的计算量和资源消耗,我相信JMeter的InfluxdbBackendListener的这种处理方式,肯定也有这方面的考量。

    原始的采样数据,在生成的JTL文件中都有,精确到了每个请求,我们在压测后统一回传服务器做异步处理,不存在资源瓶颈问题,用户最多只需等待几分钟。

    2021-07-20 21:15:29

  • ask001

    2021-07-15 22:16:58

    问下基于获取和展示实时数据(热数据)这块,如果要用多台压测机的化也是用master-slave 这种模式吗?这种模式压测过程中slave会把采样结果传回master机器,master机器统一计算后再入influxdb(比如5秒内的所有采样结果计算下在发送到influxdb),这种模式如果tps大的化,master是不是还会有瓶颈,还是说没用master-slave这种模式的?
    作者回复

    不是传统的master-slave模式。

    实时数据的采样,是每个slave在压测时直接将数据上报至InfluxDB的。每一轮压测,平台都会生成一个唯一的triggerId,所有slave上报数据时均带上值为这个triggerId的TAG,以便InfluxDB聚合。

    master则是直接从InfluxDB中取出数据,进行一定的加工(根据具体指标进行求和或求平均值等),再推送数据展示到前端。

    显然,master的计算量不大(而且都是用了InfluxDB自带的聚合方法),所以瓶颈一般不会出现在master。反倒是slave在上报数据时,如果TPS很高可能会出现瓶颈,关于这一点可以看一下JMeter的InfluxdbBackendListener的实现,简单说,数据上报是通过消息队列异步进行的,且这个队列是有长度上限的(可以设置),通过这种方式避免过多的影响slave的压测资源消耗。

    2021-07-16 22:23:30