最近需要對改造的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:\soft\jmeter\apache-jmeter-3.2。
2)配置JMeter環境變數,增加變數JMETER_HOME,值為“D:\soft\jmeter\apache-jmeter-3.2”,修改變數CLASSPATH,增加“%JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;% JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib\logkit-1.2.jar;”
3)執行JMeter目錄下的bin\jmeter.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目錄lib\ext下,並將工程依賴的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下。