zoukankan      html  css  js  c++  java
  • linux环境下Jmeter分布式环境搭建及执行

    一、使用Jmeter分布式测试的背景

    1、GUI、非GUI(即命令行)的区别

    Jmeter有两种运行方式,GUI、非GUI。

    GUI:在Windows系统上运行,图形化界面,方便收集测试结果,但是消耗压力机资源较高,容易卡死,有并发限制。

    非GUI:在Linux系统上通过命令行运行,无图形化界面,不方便收集测试结果,但是占用压力机资源较低,可以支持较大并发。

    2、GUI遇到的问题

    1)图形化界面消耗更多资源,如CPU和内存,容易使压力机达到瓶颈,从而影响测试结果。

    Jmeter是基于java程序运行的,在windows上使用Jmeter进行性能测试时,非常耗费客户机的CPU和内存,如果并发数稍微大一点(比如100、1000...并发),单台电脑的配置经常无法支持,很容易卡死,即使不卡死也会使电脑运行很慢,导致我们没办法进行其它操作。

    2)图形化界面不支持大型的负载测试和性能测试,并发较大时,jmeter会崩溃。
    综上,jmeter压测时需要使用非GUI即命令行执行,减少资源消耗。
    3、非GUI单点遇到的问题
    在使用Jmeter进行性能测试时,在不进行调优的情况下,并发用户数很难突破1000;Jmeter进行调优后,单台并发数可以突破2000。但是如果要支持更大的并发,例如:5000、20000并发,则需要使用Jmeter提供的分布式测试的功能。

    二、Jmeter分布式执行原理

    1、Jmeter分布式测试时,选择其中一台作为控制机(master),其它机器作为执行机(slave)。

    建议:一台linux作为master,多台linux作为slave。主要是避免slave压测机数据上报带来的影响。要求:slaver服务的jdk和Jmeter版本要一致,避免出现一些疑难杂症。

    2、执行时,master会把脚本发送到每台slave上,slave拿到脚本后就开始执行,slave执行时不需要启动GUI,如果引用到csv等外部的文件,则每台slave所在的机器都需要相应位置(脚本中可以指定文件路径)手工上传该文件。slave本地不需预先存储脚本,但是需要有脚本中的依赖文件(如csv文件等),并需要设置正确的路径。

    3、执行完成后,slave会把结果回传给master,master会收集所有slave的信息并汇总。

    注意:

    (1)每一台jmeter远程服务器(slave机器)都执行相同的测试计划,jmeter不会在执行期间做负载均衡,每一台服务器都会完整地运行测试计划;

    (2)采用JMeter远程模式并不会比独立运行相同数目的非GUI测试更耗费资源。但是,如果使用大量的JMeter远程服务器,可能会导致客户端过载,或者网络连接发生拥塞;

    (3)默认情况下,master机器是不执行参与生成并发数据的;

    (4)调度机(master)和执行机(slave)最好分开,由于master需要发送信息给slave并且会接收slave回传回来的测试数据,所以mater自身会有消耗,所以建议单独用一台机器作为mater。

    三、Jmeter分布式设备资源准备(根据并发数量准备,此处仅供参考)

    2台16核32G linux环境Centos7.6(代理机),1台8核16Glinux环境(控制机),linux系统版本由jmeter版本兼容环境决定,本次使用的系统是Cenos7.6,Jmeter版本5.2.1,JDK版本1.8。
    3台机器分别各自安装好jdk、jmeter。

    四、Jmeter分布式搭建

    1台作为控制机,2台作为从机(执行机)。

    1、JDK1.8安装

    1)官网下载文件

    下载链接:https://www.oracle.com/java/technologies/javase-jdk8-downloads.html
    本次使用的安装包:jdk-8u91-linux-x64.tar.gz

    2)上传文件解压

    进入安装包目录执行解压命令:tar -xzvf jdk-8u91-linux-x64.tar.gz

    3)linux环境变量配置

    执行命令vi /etc/profile,在文件底部增加如下内容(安装路径根据实际情况修改),并保存:

    JAVA_HOME=/usr/local/jdk1.8
    export JAVA_HOME
    JRE_HOME=\$JAVA_HOME/jre
    export JRE_HOME
    PATH=\$JAVA_HOME/bin:\$JRE_HOME:bin:\$PATH
    export PATH
    CLASSPATH=\$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tool.jar:\$CLASSPATH
    export CLASSPATH
    

    执行命令source /etc/profile ,生效文件修改。

    4)验证jdk安装是否成功

    执行命令java -version,显示java版本信息则表示安装成功

    2、Jmeter安装

    1)官网下载文件

    下载链接:http://jmeter.apache.org/download_jmeter.cgi 或 链接: https://pan.baidu.com/s/1mQ1y8yh0pEU8_tzyxv7zww 提取码: 33ts
    本次使用的安装包:apache-jmeter-5.2.1.tgz

    2)上传文件并解压

    进入安装包目录执行解压命令:tar zxvf apache-jmeter-5.2.1.tgz

    3)linux环境变量配置

    执行命令vi /etc/profile,在文件底部增加如下内容,并保存:

    export JMETER_HOME=/opt/apache-jmeter-5.2.1
    export CLASSPATH=${JMETER_HOME}/lib/ext/ApacheJMeter_core.jar:${JMETER_HOME}/lib/jorphan.jar:${CLASSPATH}
    export PATH=${JMETER_HOME}/bin:${PATH}
    

    执行命令source /etc/profile ,生效文件修改。

    4)验证jmeter安装是否成功

    执行命令jmeter -v,显示jmeter版本信息则表示安装成功

    5)服务授权

    如果压测启动和服务配置都是root权限,需要在linux环境下给jmeter和jmeter-server授权,命令:chmod 777 jmeter

    3、jmeter控制机配置文件修改

    1)修改jmeter.properties中的remote_hosts

    文件路径:jmeter安装路径的bin目录下
    修改点1:文件中remote_hosts值,原文件是remote_hosts=127.0.0.1,修改成remote_hosts=134.175.16.161:1099,193.112.110.50:1099,此处IP是代理机IP地址(腾讯云机器此处写内网IP)和端口按默认值则填写1099或直接写IP即可。

    修改点2:文件中server.rmi.ssl.disable值,原文件是#server.rmi.ssl.disable=false,修改成server.rmi.ssl.disable=true。若未修改则启动执行时会报错:java.io.FileNotFoundException: rmi_keystore.jks (No such file or directory),如下所示:

    2)内存修改

    方法一(推荐):修改jmeter,修改后启动命令直接使用jmeter
    使用UE软件打开该文件搜索HEAP修改最大值
    : "${HEAP:="-Xms4g -Xmx8g -XX:MaxMetaspaceSize=512m"}"

    方法二:修改jmeter.sh,修改后启动命令需使用jmeter.sh
    文件底部增加以下内容:
    java $JVM_ARGS -Xms1G -Xmx3G -XX:MaxPermSize=512m -Dapple.laf.useScreenMenuBar=true -jar dirname $0/ApacheJMeter.jar "$@"

    4、jmeter执行机(slave)配置文件修改

    slave执行机与控制机配置文件修改基本一样,不同之处在于控制机需要修改jmeter.properties文件中remote_hosts的值,添加各个执行机IP地址。

    1)修改jmeter.properties

    文件路径:jmeter安装路径的bin目录下
    修改点1:文件中server.rmi.ssl.disable值,原文件是#server.rmi.ssl.disable=false,修改成server.rmi.ssl.disable=true

    2)内存修改(参照控制机修改方法)

    3)slave执行机端优化:linux端口数量调整

    vim /etc/sysctl.conf 添加
    net.ipv4.ip_local_port_range = 1024 65000
    fs.file-max = 6553560
    net.ipv4.tcp_keepalive_probes = 3
    net.ipv4.tcp_keepalive_intvl = 3
    net.core.netdev_max_backlog = 3000
    net.core.somaxconn = 3000
    net.ipv4.tcp_keepalive_time = 1800
    net.ipv4.tcp_max_syn_backlog = 8192
    net.ipv4.tcp_fin_timeout = 30
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_rmem = 8192 4194304 8388608
    net.ipv4.tcp_wmem = 8192 4194304 8388608
    net.core.rmem_max = 8388608
    net.core.wmem_max = 8388608
    net.ipv4.tcp_timestamps = 1

    sysctl.conf文件修改生效命令:sysctl -p
    若未做此优化,会出现较多如下报错:
    Non HTTP response code: java.net.NoRouteToHostException

    4)slave执行机关闭防火墙

    分布式执行出现报错”No route to host“时需要slave执行机关闭防火墙
    查看防火墙状态(CentOS7.6需使用命令systemctl status firewalld)
    service iptables status/systemctl status firewalld
    关闭防火墙
    systemctl stop firewalld

    5、jmeter的slave执行机服务启动(两台都分别启动)

    启动命令:
    jmeter-server -Djava.rmi.server.hostname=134.175.16.161 (slave执行机本机IP) ,注意点:如果是配置内网ip,此处ip为该slave执行机对应的内网ip地址
    启动命令若未加入本机IP,可能会出现“An error occurred: Cannot start. localhost is a loopback address”错误,若想直接通过命令jmeter-server启动不加入IP可修改文件jmeter-server增加内容:RMI_HOST_DEF=-Djava.rmi.server.hostname=134.175.16.161
    备注:后台运行执行时,可在命令前面加入nohup,命令末尾加入&,例:nohup jmeter-server -Djava.rmi.server.hostname=134.175.16.161 &
    启动成功标志如下:

    6、上传压测脚本和外部读取的csv文件

    只需要上传压测脚本到控制机master服务器,节点机slave不需要上传,压测脚本自动回发到slaver执行机上;但是如果脚本中涉及从外部读取的csv文件,那该文件就需要上传到各个slaver执行机上。
    注意:参数化文件路径若只写文件名称无具体路径时,linux环境下默认读取用户目录下的文件(例:登录用户是root,则是在root目录下),windows环境默认读取的是跟脚本同目录的路径。

    7、jmeter控制机命令启动执行

    1)命令行格式
    常用格式(单机执行命令):
    jmeter -n -t [jmx脚本路径] -l [测试输出结果文件路径] -e -o [结果文件html格式存放路径] -j [测试输出结果日志]
    示例:
    jmeter -n -t /opt/testplan/xssb.jmx -l /opt/testplan/result_xssb_200user_01.jtl -e -o /opt/testplan/result_xssb_200user_01/ -j /opt/testplan/result_xssb_200user_01.log
    分布式执行,启动所有slave机执行命令:
    jmeter -n -t [jmx脚本路径] -r -l [测试输出结果文件路径] -j [测试输出结果日志]
    例:jmeter -n -t /opt/testplan/xssb.jmx -r -l /opt/testplan/result_xssb_200.jtl -j /opt/testplan/result_xssb_200.log

    分布式执行,启动指定slave机执行命令:
    jmeter -n -t [jmx脚本路径] -R ip1,ip2 -l [测试输出结果文件路径] -j [测试输出结果日志]
    例:jmeter -n -t /opt/testplanHn/count.jmx -R 172.16.0.12,172.16.0.7 -l /opt/testplanHn/count88.jtl -j /opt/testplanHn/result_count88.log

    (不推荐)启动所有slave机执行命令并将结果转成html报告格式:
    jmeter -n -t [jmx脚本路径] -r -l [测试输出结果文件路径] -e -o [结果文件html格式存放路径] -j [测试输出结果日志]
    不推荐原因说明:转成html文件占用空间大,下载效率慢,建议下载jtl文件在本机直接,本处仅供了解。
    例:jmeter -n -t /opt/testplanHn/count.jmx -r -l /opt/testplanHn/result_count_8.jtl -e -o /opt/testplanHn/result_count_8/ -j /opt/testplanHn/result_count_8.log

    (推荐)下载jtl文件到本机windows电脑上,将jtl文件转成html报告命令:
    jmeter -g [jtl结果路径] -o [结果文件html格式存放路径] ,注意:html存放文件夹需为空或不存在,否则生成会失败,失败信息:folder is not empty
    例:jmeter -g F:\perf200218\result_login_500\resultCq_login_500_01.jtl -o F:\perf200218\result_login_500\html
    2)解读命令行参数
    -g : 指定已存在的测试结果文件
    -n :以非GUI形式运行Jmeter,表示 non gui mode,就是非图形化模式

    -t :source.jmx 脚本路径,

    即testplan,后跟要运行的jmeter脚本的路径和脚本名称。

    若指定路径下没有指定名称的脚本,则自动创建。

    若没有路径只写脚本名称,则默认是在当前目录查找或创建。

    -r:启动所有slave机执行,远程将所有slave机启动用在分布式测试场景下,不是分布式测试只是单点就不需要-r

    -R:指定远程连接的slave机器的ip地址,多个ip之间用逗号隔开

    -l :result.jtl 运行结果保存路径(.jtl),此文件必须不存在,重新执行需要手动删除已经生成的jtl文件

    -j:存放日志路径。注意:不要写太多日志,否则转成html报告时会出现内存溢出错误。分布式时,该处是控制机日志,非执行机日志,执行机日志放置路径是各个执行机的/root/jmeter-server.log。脚本中输出的日志都是在执行机上。但是当输出日志时过大时转成html报告会报错Java Heap space,如下图所示:

    -e :在脚本运行结束后生成html报告

    -o :用于存放html报告的目录,指定的文件及文件夹,必须不存在 ,否则执行会失败。

    注意:-r/R启动远程服务,即分布式执行启动slave机时,首先在这些slave执行机上启动jmeter-server的服务

    3)分布式执行,启动成功标志如下:

    五、Jmeter分布式执行注意点

    单个压测机线程数配置<=1500,太多性能损耗较大,延时高。

    1、分布式线程数设置

    分布式运行时,总并发数是脚本中设置的线程数 * slave机的个数,如线程数设置为4,使用2个slave机运行,则总并发数是4*2=8.
    例:执行1000并发时,脚本中设置的线程数=并发数/slave机的个数即1000/2=500。
    分布式执行时,可通过最后一条summary=的Finished值进行判断本次执行的并发数是多少。
    例:脚本设置线程数4,代理机2台,分布式执行时,该处的Finished是8,即进行的并发数是8

    summary=为总的数据,368是请求数,23.9/s是TPS,Avg是平均响应时间单位ms,这里是0.319s,Err是错误率
    其中主要有两种信息:summary + 和summary =,其它项都是类似的

    summary + 203 in 00:00:15:在30秒内增加了203个请求,其中时间间隔由配置文件中的interval统计频率的值决定

    summary = 368 in 00:00:15:在15秒内产生的总请求数是3685个,其中的时间段是从脚本运行开始计算到当前时间为止,一般在脚本运行过程中主要关注summary=信息即可

    23.9/s:系统每秒处理的请求数,相当于TPS

    Avg: 319:平均响应时间(单位ms)

    Min: 178:最小响应时间(单位ms)

    Max: 1761:最大响应时间(单位ms)

    Err: 0 (0.00%):错误数/率

    Active: 1:活动的线程数

    2、Jmeter传参命令在分布式时不起作用(Jmeter缺陷)

    Jmeter单机可使用传参命令动态修改线程数,但在分布式时不起作用,此问题是Jmeter存在的缺陷。故分布式时,只能通过本机修改线程数后再上传执行。
    Jmeter单机传参命令参考如下(脚本中需设置对应的线程参数):
    jmeter -Jthreads1=4 -Jrampup=1 -Jduration=20 -n -t /opt/testplanHn/count.jmx -l /opt/testplanHn/result_count_new4.jtl -j /opt/testplanHn/result_count_new4.log

    3、分布式的多台单点替代方法

    当分布式部署存在问题无法解决或者不想使用分布式时,可采取多台单点执行替代方法,统计数据时,并发数=单点数量并发数相加,TPS=多台单点的TPS相加,平均响应时间=多台单点平均响应时间相加/单点数量。
    例:2台单点同时执行,并发数=2台单点并发数相加,TPS=2台单点的TPS相加,平均响应时间=2台单点平均响应时间的平均值。

    4、单点命令行执行,保存响应结果(该方法只适应单点,且转成html报告存在问题,此处仅供了解,后续有新方法再更新。目前分布式的保存响应结果还待研究。)

    Jmeter为了减少压力机负担,默认是不保存响应结果。需要做以下设置:
    修改bin目录下的user.properties文件,追加配置:

    jmeter.save.saveservice.output_format=xml
    jmeter.save.saveservice.response_data=true
    jmeter.save.saveservice.samplerData=true
    jmeter.save.saveservice.requestHeaders=true
    jmeter.save.saveservice.url=true
    jmeter.save.saveservice.responseHeaders=true

    但是该配置添加后,将jtl转化成html格式报告出错(原因:转换成html格式需要jmeter.save.saveservice.output_format=csv,linux环境默认是该配置),出错信息如下:

    Error in NonGUIDriver java.lang.IllegalArgumentException: Report generation requires csv output format, check 'jmeter.save.saveservice.output_format' property
    An error occurred: Error in NonGUIDriver Report generation requires csv output format, check 'jmeter.save.saveservice.output_format' property
    所以以上保存错误信息的方法不可行。

    通过以上设置生成的jtl文件,在windows查看会出现乱码,需要修改本机windows机器Jmeter配置:修改jmeter.properties 中的sampleresult.default.encoding=UTF-8

    5、分布式保存错误响应结果

    使用BeanShell Assertion元件进行断言操作。注意:不可写太多日志内容,以免影响性能,及转换成html时出现内存报错。

    例:

    
    String response = "";
    
    String Str = "JMeter2";
    
    String response = "${title}";
    
    //response = prev.getResponseDataAsString();//获取当前请求响应结果
    
    if(response == "")
    
    {
    
     Failure = true;
    
     FailureMessage = "系统无响应,获取不到响应数据";
    
     log.info(FailurMessage);
    
    //}else if(response.contains(Str)==false){
    
    }else if(response.equals(Str)==false){
    
     Failure = true;
    
     String msg = "\n系统返回响应结果与预期结果不一致!请排查是性能问题,还是程序代码问题";
    
     FailureMessage = msg + "\n" + "期望结果:\n" + Str + "\n" + "响应内容:\n" + "${title}" + "\n";
    
     log.info(FailureMessage); 
    
    }
    
    

    分布式时,.log日志不存在控制机,而是执行机jmeter-server.log(默认在用户目录下如root目录)中,但是分布式的jtl文件转成html报告是可以看到报错日志。
    执行机中日志显示如下所示:

    控制机.jtl文件转换成html时响应结果显示Unicode编码,可通过网站http://tool.chinaz.com/tools/unicode.aspx 进行转码:


    附录

    1、windows版本jmeter内存修改

    1)修改jmeter.bat文件,搜索HEAP

    2)验证内存修改是否生效

    运行文件 D:\Program Files\Java\jdk1.8.0_101\bin\jvisualvm.exe,查看本地Jmeter的信息,如下所示:

  • 相关阅读:
    java使用io流读取windows文件乱码问题
    java的io字符流关闭和刷新.flush();
    java使用io流实现图片复制
    java8新特性-函数式接口详细讲解及案例
    java8的lambda过滤list遍历集合,排序
    java复制对象,复制对象属性,只可复制两个对象想同的属性名。也可自定义只复制需要的属性。
    详讲KMP算法
    java栈和队列
    请求中文乱码解决
    idea创建servlet步骤
  • 原文地址:https://www.cnblogs.com/seamy/p/15654545.html
Copyright © 2011-2022 走看看