压测JMeter经验分享文档-Concurrency Thread Group

147 阅读11分钟

一、环境搭建与基础配置

1、安装指南

(1)Java环境校验

  ——JMeter是使用java编写的,必须安装java环境,推荐安装jdk11;

参考:blog.csdn.net/weixin_6153…

           blog.csdn.net/weixin_4258…

 

(2)JMeter下载与启动

—Part1:下载—

     链接:jmeter.apache.org/download_jm…

image.png

—Part2:启动—

    解压压缩包后进入bin文件夹,打开对应路径终端,输入jemter启动;

image.png

2、必装插件

通过jmeter官网下载的jmeter 并没有jmeter plugins manager,也没有常用的stepping thread group、RT和TPS UI视图界面需要自己下载安装;

1.从官网下载jmeter plugins manager的jar包

下载地址:jmeter-plugins.org/install/Ins…

2.按照提示文案,将下载的jar包放在jmeter的lib/ext目录下
3.启动jmeter

就可以在菜单栏 选项下找到plugins Manager,点击plugins Manager就会弹出一下界面

常用插件:RT和TPS UI视图界面

二、测试计划示例

Jmeter-http接口脚本

一般分五个步骤:(1)添加线程组 (2)添加http请求 (3)在http请求中写入接入url、路径、请求方式和参数 (4)添加查看结果树 (5)调用接口、查看返回值;

1、并发线程组:Concurrency Thread Group

image.png

  • Target Concurrency:目标并发(线程数),例如设置为5000表示最终会有5000个线程同时运行;
  • Ramp Up Time:启动时间;若设置 1 min,则目标线程在1 imn内全部启动;
  • Ramp-Up Steps Count:阶梯次数;若设置 10 ,则目标线程在 1min 内分六次阶梯加压(启动线程);每次启动的线程数 = 目标线程数 / 阶梯次数 = 5000 / 10 = 500;
  • Hold Target Rate Time:持续负载运行时间;若设置 4320(min) ,则启动完所有线程后,持续负载运行 72小时,然后再结束;
  • Time Unit:时间单位(分钟或者秒);
  • Thread Iterations Limit: 线程迭代次数限制(循环次数);默认为空,理解成永远,如果运行时间到达Ramp Up Time + Hold Target Rate Time,则停止运行线程 【不建议设置该值】;
  • Log Threads Status into File: 将线程状态记录到文件中(将线程启动和线程停止事件保存为日志文件);

2、HTTP请求

image.png

  • 协议:http && https
  • 服务器名称或ip:如172.16.195.143
  • 方法:一般Post && Get
  • 路径:你向服务器发送请求的路径(api)
  • Parameters:请求的参数/ Body Data:post数据

3、HTTP信息头管理器

image.png

  • 设置通用头部信息:为所有的 HTTP 请求设置相同的头部信息,减少重复配置;
  • 覆盖默认头部:如果某些请求需要不同的头部信息,可以在具体的 HTTP 请求中覆盖这些默认设置;

4、CSV文件设置

——从外部 csv 文件读取数据出来作为变量

image.png

  • 文件名:csv 文件路径,可以是绝对路径或者相对路径(建议设置成相对路径,填写相对于脚本的路径,后续远程压测或迁移时,可以更好的找到文件)

  • 文件编码:编码格式,与所选文件编码格式保持一致

  • 变量名称:如果文件中只有一个变量(csv文件列名),直接写变量名,如果有多个变量,用英文的逗号隔开(例:var1,var2)

  • 忽略首行:设置为 True 时,从文件第二行开始读取,此时文件第一行为变量名,例:var1,var2;设置为 True

  • 分隔符(用 ‘\t’ 代替制表符) :根据文件中的分隔符进行填写,默认:,

  • 是否允许带引号

    • True:参数文件包含引号时,实际的数据为引号中的数据。比如参数文件中的数据为"1,2",当使用该参数时,实际取得值为1,2
    • False:参数文件包含引号时,实际取得值为全部的值。比如参数文件中的数据为"1,2",当使用该参数时,实际取得值为"1,2"会取成两个参数
  • 遇到文件结束符再次循环
    • True:参数文件中的数据循环使用,测试按照线程组中的设置执行。比如csv 文件共有 10 条记录,但线程数有 15 个,循环 10 次后,重头开始循环取值
    • False:参数文件不再循环遍历取值
  • 遇到文件结束符停止线程:True:当执行完参数文件中所有参数后,直接停止线程,同理,false即不停止

  • 线程共享模式

    • 所有线程(All threads):参数文件对所有线程共享,这包括同一测试计划中的不同线程组(测试计划下的所有线程组下的所有线程共享参数文件,所有线程之前参数取值互相影响,线程在同一次迭代下取值相同)
    • 当前线程组(Current thread group): 只对当前线程组中的线程共享(当前线程组下的所有线程公用一个参数文件,同一个线程组下的线程之前取值相互影响,线程在同一次迭代下取值相同)
    • 当前线程(Current thread): 仅当前线程获取(即每个线程获取一个参数文件,各个线程之间参数取值互不影响,线程在同一次迭代下取值相同)

5、聚合报告/汇总报告

(1)聚合报告

image.png

  • Label:就是请求名称
  • #Samples:总线程数,值 = 线程数 * 循环次数
  • Average:单个请求的平均响应时间,值 = 总运行时间 / 发送到服务器的总请求数
  • Median、90%line、95%line、99%line分别代表50%的用户响应时间、90%的用户响应时间、95%的用户响应时间、99%的用户响应时间,也就是有百分之多少的请求小于这个值。其中,90%line是性能测试中比较重要的一个衡量指标。
  •  Min:最小响应时间 
  • Max:最大响应时间
  • Error% :错误率,发生错误的请求 / 总请求数
  • Throughput:吞吐量,表示每秒完成的请求数
  • KB/sec:以每秒接收/发送的千字节为单位测量的吞吐量

(2)汇总报告

image.png

  • 平均值:一组样本的平均响应时间
  • 最小值:一组样本中最短的响应时间
  • 最大值:一组样本中最长的响应时间
  • 平均字节数:样本响应数据的平均大小,以字节为单位

6、查看结果树

    显示所有样本响应数据、花费时间、响应代码等信息;

image.png 查看响应的方法有以下15种,详细信息参考:www.cnblogs.com/dabeen/p/18…

  • Text:显示响应中包含的所有文本
  • Regexp Tester(正则表达式测试) :可用于正则表达式测试
  • Boundary Extractor Tester(边界提取器测试) :可用于左右边界测试
  • CSS/JQuery Tester(CSS选择器测试) :可用于属性测试
  • JSON Path Tester(JSON路径测试) :可用于JSON路径测试
  • XPath2 Tester(XPath2测试)
  • JSON JMESPath Tester
  • XPath Tester(XPath测试)
  • HTML:将响应呈现为HTML
  • HTML Source Formatted(HTML源格式) :呈现HTML源代码
  • HTML (download resources)(HTML下载资源) :呈现HTML代码引用的图像、样式表等
  • Document:文档视图将显示从各种类型的文档中提取文本、以及一些“多媒体”文件的数据
  • JSON:以树样式展示json响应数据
  • XML:以树样式显示响应
  • Browser**
    **

7、Response Times Over Time

即TRT:事务响应时间,性能测试中,最重要的2个指标之一。该插件的主要作用是在测试脚本执行过程中,监控查看响应时间的实时平均值、整体响应时间走向等。

image.png

8、Transactions per Second

即TPS:每秒事务数,性能测试中,最重要的两个指标的另外一个。该插件的作用是在测试脚本执行过程中,监控查看服务器的TPS表现————比如整体趋势、实时平均值走向、稳定性等。

image.png

9、Constant Throughput Timer(定时器)

image.png

  • Target Throughput(minute) :每分钟吞吐量

  • Calculate Ghtrouhput based on:吞吐量基于下面几种方式计算

    (1)this thread only:基于当前线程。如Number of Thread=5.则TPS=5*2=10
    (2)all active threads:所有活跃的线程
    (3)all active threads in current thread group:当前线程组所有活跃的线程
    (4)all active thread(shared):所有活跃的线程(共享)
    (5)all active threads in current thread group(shared):当前线程组中的所有活跃的线程(共享)

10、Save Responses to a file

使用场景:当结果太大,使用结果树监听器影响图形模式时,我们可以采用响应保存监听器来处理

image.png

  • Save conditions

    • Save Successful Responses only:仅保存成功响应
    • Save Failed Responses only:仅保存失败响应
    • Don’t save Transaction Controller SampleResult:不保存事务控制器样本结果
  • Save details

    • 文件名称前缀(Filename prefix (can include folders)):文件路径 + 文件前缀
    • Don’t add number to prefix:不添加数字到文件前缀
    • Don’t add content type suffix:不添加文件的后缀类型
    • Add timestamp:添加时间戳到文件前缀
    • Minimum Length of sequence number:设置文件名称最小的序列号

三、日志文件分析脚本

分析日志文件中"写入vm成功"相关的性能数据,主要计算响应时间(RT)的统计指标和写入样本总量;

#!/bin/bash

# 检查是否提供了足够的参数
if [ $# -lt 1 ]; then
    echo "错误: 请指定日志文件路径"
    echo "用法: $0 <日志文件路径> [开始时间] [结束时间]"
    echo "时间格式: YYYY-MM-DD HH:MM:SS[.mmm]"
    exit 1
fi

log_file="$1"
start_time="$2"
end_time="$3"

# 检查日志文件是否存在
if [ ! -f "$log_file" ]; then
    echo "错误: 日志文件 $log_file 不存在"
    exit 1
fi

grep "写入vm成功" "$log_file" | awk -v start_time="$start_time" -v end_time="$end_time" '
BEGIN {
    # 初始化时间范围变量
    if (start_time != "") {
        gsub(/[-:.]/, " ", start_time)
        split(start_time, st, " ")
        start_ts = mktime(st[1] " " st[2] " " st[3] " " st[4] " " st[5] " " st[6]) * 1000 + (st[7] == "" ? 0 : st[7])
    } else {
        start_ts = 0
    }
    
    if (end_time != "") {
        gsub(/[-:.]/, " ", end_time)
        split(end_time, et, " ")
        end_ts = mktime(et[1] " " et[2] " " et[3] " " et[4] " " et[5] " " et[6]) * 1000 + (et[7] == "" ? 0 : et[7])
    } else {
        end_ts = 9999999999999  # 未来很久的时间
    }
}
{
    # 提取日志时间
    log_time = $1 " " $2
    
    # 转换日志时间为时间戳
    gsub(/[-:.]/, " ", log_time)
    split(log_time, dt, " ")
    current_ts = mktime(dt[1] " " dt[2] " " dt[3] " " dt[4] " " dt[5] " " dt[6]) * 1000 + (dt[7] == "" ? 0 : dt[7])
    
    # 检查时间范围
    if (current_ts < start_ts || current_ts > end_ts) {
        next  # 跳过不在时间范围内的记录
    }
    
    if (match($0, /[0-9]{13}/, ts_arr)) {
        start_ms = ts_arr[0]
        end_ms = current_ts
        rt = end_ms - start_ms
        
        # 提取批次数并累加
        if (match($0, /批次: ([0-9]+)/, batch_arr)) {
            total_samples += batch_arr[1]
        }
        
        # 只统计合理的 RT 值
        if (rt >= 0 && rt <= 10000) {
            rts[++n] = rt
            sum += rt
            if (rt > max || max == "") max = rt
            if (rt < min || min == "") min = rt
        }
    }
}
END {
    if (n > 0) {
        # 计算平均值
        avg = sum / n
        
        # 计算 P90
        asort(rts)
        p90_pos = int(n * 0.9)
        if (p90_pos < 1) p90_pos = 1
        p90 = rts[p90_pos]
        
        # 显示实际统计的时间范围
        printf "统计时间范围: "
        if (start_ts == 0) {
            printf "开始"
        } else {
            printf "%s", strftime("%Y-%m-%d %H:%M:%S", start_ts/1000)
            if (start_ts % 1000 > 0) {
                printf ".%03d", start_ts % 1000
            }
        }
        printf " 至 "
        if (end_ts == 9999999999999) {
            printf "结束"
        } else {
            printf "%s", strftime("%Y-%m-%d %H:%M:%S", end_ts/1000)
            if (end_ts % 1000 > 0) {
                printf ".%03d", end_ts % 1000
            }
        }
        printf "\n"
        
        printf "写入样本总量: %d\n", total_samples
        printf "RT (ms):\nMax: %.2f\nMin: %.2f\nAvg: %.2f\nP90: %.2f\nCount: %d\n", 
               max, min, avg, p90, n
    } else {
        print "未找到有效日志"
    }
}'

(1)基础使用方法

        ./calculate_rt_stats.sh 日志文件路径

(2)带时间范围的用法

    ./calculate_rt_stats.sh 日志文件路径 "开始时间" "结束时间"

        例如:./calculate_rt_stats.sh app.log "2025-01-01 10:00:00" "2025-01-01 11:00:00"

(3)输出说明

  • 实际统计的时间范围
  • 写入样本总量
  • RT统计信息:最大值、最小值、平均值、P90值和有效记录数

(4)注意

  • 如果没有提供时间参数,会处理整个日志文件
  • 如果找不到匹配的日志,会显示"未找到有效日志"

四、压测踩坑经验分享

1、重新开始RUN之前,要清除当前计划中国中的所有监听器的执行结果;

image.png

2、导出.jmx文件之前,要先Save保存整个测试计划;

image.png

3、jmeter内存不足

JMeter 默认内存较小,大并发测试时修改bin\jmeter.bat(Windows)或jmeter.sh(Linux/Mac)中的HEAP参数(如set HEAP=-Xms2g -Xmx4g)。

4、正式压测执行时,GUI模式会占用大量系统资源(CPU/内存),影响压测结果的准确性

脚本开发与调试阶段、 实时监控测试结果时, 可开启图形化界面(GUI), 执行高并发测试(如1000+线程)或长时间稳定性测试时,通过命令行启动


运行命令格式:


./jmeter -n -t [jmx脚本路径] -l [测试输出文件路径]