记一次完整的java项目压力测试
总结:通过这次压力测试,增加了对程序的理解;假定正常情况下方法执行时间为2秒,吞吐量为100/s,则并发为200/s;假设用户可接受范围为10s,那么并发量可以继续增加到1000/s,到这个时候一切还都正常,若想继续提高并发量,我们可以优化吞吐量,增加tomcat的线程数和mysql的连接数;当吞吐量和并发量都达到一定程度,我们的JVM已经爆仓,则到了java开发最喜欢的JVM调优环节。
本着压测结果不能超脱实际情况裸奔的前提,压测参数在特定情况下参照:
1.接口最大响应时间(时间太长,客户要发彪);
2.带宽大小(线上机器带宽被运维限制,你想飞,飞不起来;内部带宽大小最好通知运维人员,防止影响路由其他业务);
3.CPU(CPU爆顶,影响运维,和运维人员商定高峰CPU值)
4.JVM(JVM溢出还想啥啊,优化程序或者考虑加机器分流)
5.mysql连接数(mysql默认最大可以达到16384,安装完默认为100,一般运维人员会根据需要进行更改,考虑多业务同数据库或者集群部署的问题,请一定听从运维人员的建议)
6.待研究补充。
先记录这次的技术点:
JVM监控使用的是java自带jvisualvm.exe,在java安装目录jdk1.*/bin下;
使用教程:
1.服务器先要添加jmx用户名和密码,我的主机为linux,把jdk*/jre/lib/management/jmxremote.password.template文件拷贝到工程目录中(方便jvm参数配置);
-
cp /apps/jdk1.8.0_112/jre/lib/management/jmxremote.password.template /apps/dt/
-
mv jmxremote.password.template jmxremote.password
-
vim jmxremote.password
2.编辑jmxremote.password最下面两个用户#打开,如果想增加用户或者修改用户名需要在jmxremote.access声明权限才可以访问到。
chmod 0400 jmxremote.password
3.编辑项目的sh启动文件或者tomcat的catalina.sh,JAVA_OPTS中添加如下参数(注意参数之间的空格分开)
-
-Xms2g -Xmx2g -XX:PermSize=64m //jvm内存参数,请百度。
-
-server
-
-Dcom.sun.management.jmxremote.ssl=false //是否使用ssl
-
-Dcom.sun.management.jmxremote.port=10090 //jmx监控端口
-
-Dcom.sun.management.jmxremote.password.file=jmxremote.password //远程监控用户和密码文件
4.启动java项目,服务器工作就已经完成了。在本地打开jvisualvm.exe,添加远程主机,添加JMX监控,端口必填,用户名和口令需要和服务器上的jmx用户一致。
jmeter请到apache jmeter官网下载,下载完成,本地编写jmx测试脚本(如何编写请自行百度)
流程:
1.将编写好的jmx发送到linux服务器,linux下载jmeter包或者上传本地的jmeter。
2.配置jmeter命令,方便执行脚本;
-
vim /etc/profile
-
-
export JMETER_HOME=/dt/apache-jmeter-3.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
-
jmeter -v
3.执行jmx脚本,并记录测试日志jtl文件。
jmeter -n -t 测试.jmx -l log.jtl
4.把log.jtl拿到本地在jmeter中各种报告导入查看。
一、测试目的、准备及条件
- 测试目的:得到我们的程序最优最大并发量,机器吞吐量(处理速度),带宽、计算力、JVM内存等情况,方便后续程序调优,方便后续给出运维建议。
- 准备及条件
- 测试机配置:
操作系统 |
CentOS release 6.8 |
CPU |
Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz |
内存 |
4G |
带宽 |
本机部署,本机测试,带宽忽略 |
IP |
192.168.1.149:11090 |
路由 |
包含上百台办公设备的路由 |
- JVM参数配置:
<pre class="has" name="code"><code class="hljs java">MEM_OPTS=<span class="hljs-string">"-Xms2g -Xmx2g -XX:PermSize=64m -server -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=10090 -Dcom.sun.management.jmxremote.password.file=jmxremote.password"</span></code><div class="hljs-button signin" data-title="登录后复制" onclick="hljs.signin(event)"></div></pre>
</li>
<li>数据库连接池:<span style="color:#f33b45;"><strong>如果压测程序依赖数据库数据操作,那么数据库最大连接数是影响压测性能的一个重要因素,连接池在单个程序中并不是越大越好,因为所有程序共享一个数据库,某个程序连接数沾满,会造成其他程序无法访问数据库。所以这里需要跟运维人员沟通后,在确认连接数的大小设置。</strong></span>
<pre class="has" name="code"><code class="hljs python"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#最大连接数据库连接数,设 0 为没有限制</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">spring.datasource.max-active=<span class="hljs-number">20</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#最大等待连接中的数量,设 0 为没有限制</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">spring.datasource.min-idle=<span class="hljs-number">8</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#连接初始数量</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">spring.datasource.initial-size=<span class="hljs-number">10</span></div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" onclick="hljs.signin(event)"></div></pre> <p><span style="color:#000000;font-family:Consolas, Inconsolata, Courier, monospace;"> </span></p>
</li>
<li>tomcat线程池:<span style="color:#f33b45;"><strong>假设一个并发数占用一个线程(BIO方式,实际情况使用NIO或APR方式,并发数可以比线程数大很多),高并发在数据库和CPU和JVM内存中任意一个为爆满情况下,增大tomcat线程数,可以提高单个服务并发数。</strong></span>
<pre class="has" name="code"><code class="hljs xml"><ol class="hljs-ln" style="width:909px"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"><<span class="hljs-name">Connector</span> <span class="hljs-attr"><wdautohl-customtag style="font-weight:bold;color:red;font-size:inherit;display:inline;" id="wdautohl_id_3" class="wdautohl_ZXhlY3V0b3I_">executor</wdautohl-customtag></span>=<span class="hljs-string">"tomcatThreadPool"</span> </span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-attr">port</span>=<span class="hljs-string">"8080"</span> <span class="hljs-attr">protocol</span>=<span class="hljs-string">"HTTP/1.1"</span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-attr">connectionTimeout</span>=<span class="hljs-string">"20000"</span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-attr">redirectPort</span>=<span class="hljs-string">"8443"</span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-attr">minProcessors</span>=<span class="hljs-string">"20"</span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-attr">maxProcessors</span>=<span class="hljs-string">"300"</span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-attr">acceptCount</span>=<span class="hljs-string">"1000"</span>/></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">executor:表示使用该参数值对应的线程池;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">minProcessors:服务器启动时创建的处理请求的线程数;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">maxProcessors:最大可以创建的处理请求的线程数;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" onclick="hljs.signin(event)"></div></pre> <p> </p>
</li>
<li><strong>工具</strong>:使用jmeter命令在本机测试,VisualVM远程jvm状态监控。</li>
<li><strong>条件</strong>:mysql数据库:单库varchar查询,插入需要判断实际情况,如果查询与插入每次都需要执行,则每秒中最多执行200次,<span style="color:#f33b45;">请求时间计算:</span>选用OCR接口,①将上传文件到我们服务器的响应时间看做On,②文件上传至提供商服务器进行识别的时间看做On,我们对接口中②步骤做挡板,测试结果中响应时间*2作为最终响应时间;<span style="color:#f33b45;">有效请求的时间划定:</span>假定业务方一次图片识别得到结果的最大可接受时间为10s,则一旦超过10s则认为此结果为无效数据;<span style="color:#f33b45;">有效结果认定</span>:需满足在10s内完成请求且能拿到接口结果才可算是成功的请求;<span style="color:#f33b45;">业务产品要求:</span>非数据问题的接口报错绝对不可接受,此情况为运维机器层面的问题,压力结果需到此为止;</li>
二、总结及建议
以如上机器配置和条件,我们分别抽样了500/1000/800/700/600,最终600并发量为最优,结果无Error产生,机器吞吐量维持在200-300之间,每秒发送数据240M,响应时间平均为2.1s左右,jvm运行正常,5-10分钟时间运行并没有出现jvm异常的情况。
后续我们选择600并发进行16小时高并发测试,早晨8点到晚上12点,jvm无异常出现,日志正常。
综合以上结论,理论上无挡板的完整请求响应时间为4.2s左右,吞吐量在100-150之间,并发最优为600。
- 测试附件
下图为:500并发到800并发的jvm情况
下图为聚合报告,顺序(按并发量):500-600-700-800-1000
Label:每个JMeter的element的Name值。例如HTTP Request的Name
#Samples:发出请求数量。如第三行记录,模拟20个用户,循环100次,所以显示了2000
Average:平均响应时间(单位:)。默认是单个Request的平均响应时间,当使用了Transaction Controller时,也可以以Transaction为单位显示平均响应时间
Median:中位数,也就是50%用户的响应时间
90%Line:90%用户的响应时间
95%Line:95%用户的响应时间
99%Line:99%用户的响应时间
注:为什么要有*%用户响应时间?因为在评估一次测试的结果时,仅仅有平均事物响应时间是不够的。假如有一次测试,总共有100个请求被响应,其中最小响应时间为0.02秒,最大响应时间为110秒,平均事务响应时间为4.7秒,你会不会想到最小和最大响应时间如此大的偏差是否会导致平均值本身并不可信?
我们可以在95 th之后继续添加96/ 97/ 98/ 99/ 99.9/ 99.99 th,并利用Excel的图表功能画一条曲线,来更加清晰表现出系统响应时间的分布情况。这时候你也许会发现,那个最大值的出现几率只不过是千分之一甚至万分之一,而且99%的用户请求的响应时间都是在性能需求所定义的范围之内的;如下图则是最低响应时间的值出现几率是很小的,实际99%的用户请求响应时间都要20000+。
Min:最小响应时间
Max:最大响应时间
Error%:本次测试中出现错误的请求的数量/请求的总数
Throughput:吞吐量。默认情况下标示每秒完成的请求数(具体单位如下图)
KB/sec:每秒从服务器端接收到的数据量。
下图为响应时间,顺序(按并发量):500-600-700-800-1000
下图为图形结果,顺序(按并发量):500-600-700-800-1000
原文地址:https://blog.csdn.net/VcStrong/article/details/81224516
记一次完整的java项目压力测试的更多相关文章
- Java项目压力测试(待补)
JVM监控使用ava自带jvisualvm,在java安装目录jdk1.*/bin下(有很多更高级的东西 线程2000以下,太多切换太消耗.CPU使用率30%以下,更健壮
- Api项目压力测试知识荟萃
并发用户.在线用户和注册用户以及彼此之间的换算方法(估算模型).系统的最大并发用户数根据注册用户数来获得,换算方法一般是注册总人数的5%-20%之间:系统的并发数根据在线人数来获得,换算方法一般是在3 ...
- Java实现压力测试---可输出请求信息、error信息
import java.io.; import java.net.; import java.util.; import java.util.concurrent.; public class Tes ...
- 项目压力测试软件 -- LoadRunner 11.0 的安装、汉化和破解
重要说明: LoadRunner 11.0 只支持Win7,32位系统:不支持Win7,64位系统[ Win7,64位 我反复安装都没有成功!] 一.下载安装.汉化.破解文件: 我的下 ...
- Eclipse JAVA项目的 目录结构 和 导入
说明:本文所有测试以java工程为例: 1. Eclipse下的java工程目录 eclipse的基本工程目录叫做workspace,每个运行时的eclipse实例只能对应一个workspace,也就 ...
- [IntelliJ IDEA入门] 新建一个Java项目
新建一个Project 是否有JDK配置 选择JavaEE 点击Next 项目路径和文件 .idea (directory based) 创建项目的时候自动创建一个 .idea 的项目配置目录来保存项 ...
- Gradle入门(3):构建第一个Java项目
Gradle插件通过引入特定领域的约定和任务来构建你的项目.Java插件是Gradle自身装载的一个插件.Java插件提供的基本功能远比源代码编译和打包多.它为你的项目建立了一个标准的项目布局,并确保 ...
- Java基础学习总结(70)——开发Java项目常用的工具汇总
要想全面了解java开发工具,我们首先需要先了解一下java程序的开发过程,通过这个过程我们能够了解到java开发都需要用到那些工具. 首先我们先了解完整项目开发过程,如图所示: 从上图中我们能看到一 ...
- idea创建普通java项目以及maven创建项目过程(转)
1. idea创建一个普通项目流程 http://blog.csdn.net/testcs_dn/article/details/52303941 2. idea创建maven项目流程 http:// ...
随机推荐
- 域名与服务器 ip地址的理解
域名 服务器 ip地址具有怎样的关系呢 通俗的讲,我们访问一个网站就相当于访问一个服务器的文件,如果想要通过自己的域名来访问一个网站,首先得将域名部署到你的服务器上,然后就可以通过域名访问到你服务器上 ...
- synchronized三种使用方式,及锁的类型验证
Synchronized常用三种使用方式 1.修饰普通方法:锁对象即为当前对象 2.修饰静态方法:锁对象为当前Class对象 3.修饰代码块:锁对象为synchronized紧接着的小括号内的对象 一 ...
- dom4j工具对XML写入修改删除操作实现
import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; import ...
- linux添加用户所在群组
etc目录下面有两个文件一个passwd一个grouppasswd里gid是主组,其他组是扩展组,扩展组在/etc/group里描述.useradd username如果不指定,默认创建一个与uid相 ...
- sql中对查询出的某个字段转换查询
<select id="queryCmonByLanId" parameterType="java.util.Map" resultType=" ...
- java解析和组装json以及一些方法的理解
这是一个json格式的字符串 第一种情况(简单格式) String result = "{\"name\":\"小明\",\"age\&qu ...
- 如何优雅的给TDatetimePicker控件赋值(Delphi)
给DatetimePicker赋值时,可以通过界面设置赋值,也可以通过代码赋值. 通常,我们会给表示起始时间的dtp赋值为 00:00:00,给表示结束时间的dtp赋值为23:59:59. 代码如下: ...
- JavaScript高程第三版笔记(1-5章)
第2章:在html中使用javascript ①script标签的defer属性 <script type="text/javascript" defer="def ...
- 使用shell脚本常见的一些问题
Jdk版本:jdk-8u102-linux-x64 Tomcat版本:apache-tomcat-7.0.92 Redis版本:redis-5.0.0 由于公司项目的需要,要在多台服务器上面部署一些应 ...
- java安全停止线程
Thread.stop()是一个被废弃的方法,不被推荐使用的原因是stop方法太过于暴力,强行把执行到一半的线程终止,并且会立即释放这个线程所有的锁.会破坏了线程中引用对象的一致性. 使用判断标志位的 ...