最近需要对改造的redis缓存接口做压力测试,使用了开源压力测试工具JMeter,分享一下自己的使用经验,希望能对需要进行压力测试的开发同学有所帮助。
JMeter介绍
JMeter是Apache软件基金会下的一款开源压力测试工具,官方网址是:http://jmeter.apache.org/。JMeter可以测试静态、动态资源的性能,这些资源包括文件、Servlets 、Perl脚本、Java对象、数据库、FTP服务器等,并生成图形报告。JMeter使用Java开发,既支持可视化界面操作,也支持命令行操作。
Java请求测试(界面操作)
由于需要对改造的redis缓存接口测试,因此使用了JMeter的Java请求测试,安装和使用步骤如下所示(以Windows操作系统为例,并默认已安装、配置Java运行环境)。
1)从官网上下载JMeter并解压,例如解压至D:softjmeterapache-jmeter-3.2。
2)配置JMeter环境变量,增加变量JMETER_HOME,值为“D:softjmeterapache-jmeter-3.2”,修改变量CLASSPATH,增加“%JMETER_HOME%libextApacheJMeter_core.jar;% JMETER_HOME%libjorphan.jar;%JMETER_HOME%liblogkit-1.2.jar;”
3)执行JMeter目录下的binjmeter.bat,显示JMeter界面说明安装成功。
4)新建Java工程,在该工程中,引入JMeter目录下lib中的jar包,继承JMeter的AbstractJavaSamplerClient类,在子类中重写setupTest、teardownTest、getDefaultParameters、runTest方法,实现对缓存接口的get、set、hGet、hSet方法进行测试,子类代码如下所示。
ClientJmeter.java
package org.pos.gateway.client; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Arguments; import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient; import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; import org.apache.jmeter.samplers.SampleResult; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.filter.logging.LogLevel; import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.transport.socket.nio.NioSocketConnector; import com.fft.common.entity.DecodeType; import com.fft.common.entity.HeartbeatReq; public class ClientJmeter extends AbstractJavaSamplerClient { private IoSession session; private long start = 0;//记录测试开始时间; private long end = 0;//记录测试结束时间; private String ip; private String port = "32888"; private static String label = "heartbeat"; HeartbeatReq req; // 测试结果 private SampleResult sr; //初始化操作 @Override public void setupTest(JavaSamplerContext arg0) { NioSocketConnector connector = new NioSocketConnector(); LoggingFilter loggingFilter = new LoggingFilter(); loggingFilter.setSessionCreatedLogLevel(LogLevel.NONE);// 一个新的session被创建时触发 loggingFilter.setSessionOpenedLogLevel(LogLevel.NONE);// 一个新的session打开时触发 loggingFilter.setSessionClosedLogLevel(LogLevel.NONE);// 一个session被关闭时触发 loggingFilter.setMessageReceivedLogLevel(LogLevel.NONE);// 接收到数据时触发 loggingFilter.setMessageSentLogLevel(LogLevel.INFO);// 数据被发送后触发 loggingFilter.setSessionIdleLogLevel(LogLevel.INFO);// 一个session空闲了一定时间后触发 loggingFilter.setExceptionCaughtLogLevel(LogLevel.NONE);// 当有异常抛出时触发 connector.getFilterChain().addLast("logger", loggingFilter); connector.setConnectTimeoutMillis(30000); connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); connector.setHandler(new ClientHandler()); // 连接服务器,知道端口、地址 // ConnectFuture cf = connector.connect(new // InetSocketAddress("localhost", 8317)); ip = arg0.getParameter("ip"); port = arg0.getParameter("port"); if(StringUtils.isEmpty(ip)) { ip = "119.23.213.153"; } if(StringUtils.isEmpty(port)) { port = "32888"; } System.out.println("====server info: ip=" + ip + ", port=" + port); ConnectFuture cf = connector.connect(new InetSocketAddress(ip, Integer.parseInt(port))); // 等待连接创建完成 cf.awaitUninterruptibly(); System.out.println("test客户端连接服务器成功"); session = cf.getSession(); req = new HeartbeatReq(); req.setVersion("00"); req.setTransType(DecodeType.Heartbeat_REQ.getType()); req.setTransSeq("0"); req.setReqOrgCode("1234564"); req.setReqCode("00"); } @Override public Arguments getDefaultParameters() { Arguments arguments = new Arguments(); arguments.addArgument("ip", ip); arguments.addArgument("port", port); return arguments; } public SampleResult runTest(JavaSamplerContext arg0) { sr = new SampleResult(); sr.setSampleLabel(label); try{ sr.sampleStart(); //记录程序执行时间,以及执行结果 //发送数据 session.write(req); sr.setSuccessful(true); }catch(Throwable e){ sr.setSuccessful(false); }finally{ sr.sampleEnd(); } return sr; } /** * 获取jmeter输入的参数值 * * @return */ public void setValues(JavaSamplerContext arg0) { ip = arg0.getParameter("ip", ip); port = arg0.getParameter("port", port); } @Override public void teardownTest(JavaSamplerContext context) { end = System.currentTimeMillis(); getLogger().info("cost time: " + (end - start) + "ms"); } }
ClientHandler.java
package org.pos.gateway.client; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; public class ClientHandler extends IoHandlerAdapter { public void sessionOpened(IoSession session) throws Exception { System.out.println("测试端--会话打开"); } @Override public void messageReceived(IoSession session, Object message) throws Exception { System.out.println("客户端收到服务端的包内容:" + message); System.out.println("客户端收到服务端的应答码:" + ((String)message).substring(142,144)); System.out.println(); } @Override public void sessionClosed(IoSession session) throws Exception { System.out.println("会话关闭"); System.exit(0); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("会话异常"); super.exceptionCaught(session, cause); } @Override public void messageSent(IoSession iosession, Object obj) throws Exception { System.out.println("客户端消息发送:" + obj); super.messageSent(iosession, obj); } @Override public void sessionCreated(IoSession iosession) throws Exception { System.out.println("会话创建"); super.sessionCreated(iosession); } @Override public void sessionIdle(IoSession iosession, IdleStatus idlestatus) throws Exception { System.out.println("会话休眠"); super.sessionIdle(iosession, idlestatus); } }
5)将工程以jar包形式导出,置于JMeter目录libext下,并将工程依赖的jar包置于JMeter目录lib下,启动JMeter。右键“测试计划”添加“线程组”。右键“线程组”添加“Java请求”,右键“Java请求”添加“聚合报告”。
6)在“Java请求”中选择所写的测试类,并可以设置相关参数,在“线程组”中可以设置并发线程数和循环次数,点击上方“启动”按钮开始测试,测试完成后,可以在“聚合报告”中查看到测试结果。
问题记录:
1、Jmeter throwing error class org.bouncycastle.asn1.ASN1Primitive overrides final method equals
是导出的jar包与jmeter的jar冲突导致。
解决办法是:将第三方jar分开打包,将所有第三方jar拷贝到lib下,测试工程jar拷贝到lib/ext下。