之前写了一篇jemter的性能测试工具的使用,但是LoadRunner才算是真正重量级的性能测试工具,下面详细介绍一下java vuser协议的使用和环境参数调试。
LoadRunner性能测试工具使用:
1、新建脚本,选择java vuser协议。初步结构是
import lrapi.lr; public class Actions { //在init方法里面编写一个虚拟用户循环只执行一次的方法,如可以把协商写在里面,就可以达到每个用户协商一次之后,就不再协商的效果 public int init() throws Throwable { return 0; }//end of init //在aciton方法里面编写需要循环并发的业务方法,如交易的方法,在run_time settings中设置循环的次数。 public int action() throws Throwable { return 0; }//end of action //在end方法里面编写最后要执行的方法,如释放资源,没有可以不写。 public int end() throws Throwable { return 0; }//end of end }
2、在初始代码的基础上继续编写业务方法。需要注意的是:
1)把只需要创建一次对象的语句如:Random rd = new Random();放在init,aciton,end方法之外,可以避免在循环中创建很多的对象。但是需要注意的是如果是创建HTTP请求的对象是需要反复创建的,不能单提出来,否则执行一次之后,该连接被释放了,而没有创建新的连接,第二次就执行不下去了。
2、脚本编写完之后,将该脚本所有import的类的jar包放在一个文件夹下,点击Run Time Settings的classpath,把所有jar包都添加进去。
3、运行脚本,看看能不能成功执行,按照错误提示调试脚本。
4、接下来,可以把需要变化的值进行参数化。如商户名和AESKEY。选中值,右键选择replace with a parameter,在parameter list功能里添加需要用到的商户和AESKEY的值,将商户参数的循环方式select next row选择unqie,update value on选择once,表示为个商户只取唯一的值。aeskey的select next row选择same line as merchant。
5、接下来插入事物,把需要计算业务时间的代码前后都插入事物函数,如lr.start_transaction("pay");lr.end_transaction("pay", lr.AUTO);如果想更加详细的知道每一步操作的时间,可以多插入一些事物,如加密,解密,获取返回值等步骤均插入事物函数。
6、如果需要并发执行,还需要插入集合点函数lr.rendezvous("pay");这样在场景里并发执行的时候,所有的虚拟用户会等到都准备好之后在一个时间点执行。
7、接下来就是在场景里执行了。点击tools---create controller scenario。进入场景。并发10个用户执行5分钟。同时监控tomcat的日志。
在并发的情况下,出现了一些问题,下面针对这些问题给出解决方案。
遇到的问题1、在并发执行1分钟后,开始有报错,主要的报错是解密失败,同时tomcat挂了,不能在接受新的请求。
找到问题根源:通过监控tomcat日志,发现后期有很多的报错日志是文件打开过多。
严重: Socket accept failed java.net.SocketException: 打开的文件过多 at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408) at java.net.ServerSocket.implAccept(ServerSocket.java:462) at java.net.ServerSocket.accept(ServerSocket.java:430) at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:61) at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:352) at java.lang.Thread.run(Thread.java:662) 2013-5-16 11:38:46 org.apache.tomcat.util.net.JIoEndpoint$Acceptor run 2013-05-16 11:38:44,974 INFO [DefaultRequestDirector.java:586] - I/O exception (java.net.SocketException) caught when connecting to the target host: 打开的文件过多 2013-05-16 11:38:44,974 ERROR [CreditPay.java:167] - 信用卡支付失败 com.yibao.payapi.client.RequestApiException: 请求服务未正常返回[statuscode:404, text:<html><head><title>Apache Tomcat/6.0.29 -
解决方案:由于建立SOCKET会占用一个系统句柄,效果类似于打开了一个文件。LINUX默认的最大文件打开个数是1024(可能不同内核版本不一样),所以如果并发太多连接时就会报错。需要修改文件打开数设置。
当前设置最大打开文件数可以通过如下命令查看。 ulimit -n
这个数字说明了一个普通用户能够在一个单独会话中所能打开最大的文件数目。注意。如果是root,以下操作不能使ulimit -n的输出增加。因为用户root用户不受这个ulimit限制。只有普通用户才会受这个限制。
遇到的问题2:在虚拟用户少的时候并发没有再出现文件打开过多的错误,在并发量达到30,运行时间达到3分钟的时候,有报错:HTTP-500
找到问题根源:通过查看tomcat和程序的日志,看到有大量的http-500的错误,是nginx已经拒绝了请求。
解决方案:修改nginx配置文件
vi /etc/nginx/nginx.conf
events {
worker_connections 1024;
}
调整为
events {
worker_connections 65535;
}
最后附上我写的信用卡支付的脚本:
/* * LoadRunner Java script. (Build: _build_number_) * * Script Description: * */ import lrapi.lr; import http.HttpClient4; import http.HttpParameter; import http.HttpResp; import http.JsonUtil; import http.Testcredit; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.PostMethod; import java.util.Random; import java.util.Date; import java.text.SimpleDateFormat; import java.util.Calendar; import com.yeepay.g3.utils.common.encrypt.AES; import com.yibao.utils.des3.RSA_Encrypt; public class Actions { public String aes; Date d = new Date(); Testcredit tc = new Testcredit(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); HttpParameter parameter = new HttpParameter(); public int init() throws Throwable { String url = "http://xxxxx/xxxxx/consult"; HttpClient4 client =HttpClient4.createDefault(); String data = ""; Calendar now = Calendar.getInstance(); now.setTime(d); String dateline=format.format(now.getTime()); System.out.println(dateline); Date date = format.parse(dateline); String dates=date.getTime()/1000+""; System.out.println(dates); try { data = AES.encryptToBase64(dates, "<aes>"); } catch (Exception e) { e.printStackTrace(); } parameter.add("data", data); parameter.add("merchantaccount", "<merchant>"); HttpResp resp = new HttpResp(); try{ resp=client.doPost(url, parameter, "utf-8"); String respStr= resp.getText("utf-8"); System.out.println(respStr); aes=AES.decryptFromBase64(respStr, "<aes>"); System.out.println("aes="+aes); } catch (Exception e) { e.printStackTrace(); } client.shutdown(); return 0; }//end of init public int action() throws Throwable { StringBuilder sb = new StringBuilder(""); Random rd = new Random(); for(int i=1;i<=6;i++){ int sr=rd.nextInt(9); sb.append(String.valueOf(sr)); } String key=sb.toString(); int rds=rd.nextInt(999999); lr.start_transaction("pay"); lr.rendezvous("pay"); HttpClient client = new HttpClient(); PostMethod method = new PostMethod("http://xxxxxxxx/xxxxxxx/api/bankcard/credit/pay"); System.out.println(aes); String PUBLIC_KEY=aes; System.out.println("PUBLIC_KEY"+PUBLIC_KEY); String encryptkey = "0123456789"+key; String merchantAccount = "<merchant>"; //民生 String cardNo = "6XXXXXXXXXXXXXX"; String validthru = "XXXX"; String cvv2 = "XXX"; String phone = "13466745431"; String orderId = rds+"334234223"+key; System.out.println(orderId); Integer transtime = (int)(System.currentTimeMillis()/1000); Integer currency = 156; String amount = "50"; String productcatalog = "1"; String productName = "123"; String productDesc = "小丸子"; String userIp = "123.45.45.45"; String identityId = "a"; Integer identityType = 6; String other = "eeee"; String data = "{\"merchantaccount\":\"" + merchantAccount +"\",\"cardno\":\"" + cardNo + "\",\"validthru\":\"" + validthru + "\",\"cvv2\":\"" + cvv2 + "\",\"phone\":\"" + phone + "\",\"orderid\":\"" + orderId + "\",\"transtime\":" + transtime + ",\"currency\":" + currency + ",\"amount\":" + amount + ",\"productcatalog\":\"" + productcatalog + "\",\"productname\":\"" + productName + "\",\"productdesc\":\"" + productDesc + "\",\"userip\":\"" + userIp + "\",\"identityid\":\"" + identityId + "\",\"identitytype\":" + identityType + ",\"other\":\"" + other + "\"}"; data = AES.encryptToBase64(data, encryptkey); try { method.setParameter("merchantaccount", merchantAccount); method.setParameter("data", data); method.setParameter("encryptkey", RSA_Encrypt.encrypt(encryptkey, PUBLIC_KEY)); client.executeMethod(method); System.out.println(method.getStatusLine()); String respStr = method.getResponseBodyAsString(); System.out.println(respStr); String result = AES.decryptFromBase64(respStr, encryptkey); System.out.println(result); method.releaseConnection(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace();} lr.end_transaction("pay", lr.AUTO); return 0; }//end of action public int end() throws Throwable { return 0; }//end of end }