天天看點

又一次對Jmeter TCP Sampler實作的小改動

背景介紹

最近遇到國密改造的性能測試項目,有點小趣:

  1. 服務處理邏輯
伺服器收到封包,調用動态庫,根據封包中多個字段,動态計算出一個值,再與封包某個字段進行對比校驗,若校驗通過則認為封包合法,不通過則拒絕服務。我們把對比字段稱為校驗字段,多個字段稱為計算字段。
  1. 思路曆程

首先,考慮在測試的接口不多,為減少測試的複雜性,想到對封包中的字段進行固化,進而達到校驗字段不變的目的。

帶着想法找到開發人員看看封包的計算字段有哪些,是否有字段影響測試的準确性。

果不其然,這是不行的。每類封包的“計算字段”有可能不同,且同類封包中,字段A或字段B的固化變導緻資料庫的熱點問題。開發人員建議傳入整個封包到加密庫,線上也是如此。

考慮到開發意見,決定JMeter發送封包前調用加密庫對封包進行更新。

  1. 細項考量

與開發約定,開發提供一個Jar包(封裝加密庫的實作細節),且Bytes和String傳入參數類型統一約定為String。

根據開發人員提供的對Jar的測試代碼,實作對Tcp Sampler的小改。

TCP Sampler的小改

這是開發提供的對Jar包的測試代碼:

public class MacTest {
    public static void main(String[] args) {
        MacGenerator mg = new MacGenerator();
        //String secKey = "111111111111111111111111111111111";  //A用
        String secKey="22222222222222222222";   //B用
        String testStr = "this is a message";
        testStr = mg.genMac(testStr, secKey);
        System.out.println(testStr);
    }
}           

很簡單的代碼,生成一個執行個體,再調用執行個體方法,傳入“封包”和“KEY"值即可。

上述經在測試環境驗證成功後,參考我之前在知乎上寫過相于

動态封包長度

的處理方法。更改TCP Sampler實作如下:

import ...;
public class prelenTCPWithMacUpdateImpl extends TCPClientImpl {
    //存在其他私有成員,不重要,為減少文章長度,忽略
    //在user.properties裡配置KEY值 
    private final String secKey = JMeterUtils.getPropDefault("tcp.cipher_cn.secKey", "0");

    public prelenTCPWithMacUpdateImpl() {
        super();
    }
    @Override
    public void write(OutputStream os, String s)  throws IOException {
        //這是新增代碼的開始
        MacGenerator mg = new MacGenerator();
        String strWithMacVal = mg.genMac(s, this.secKey);
        //這裡新增代碼的結束 
        
        //這是”動态封包長度“的小改開始
        byte[] sb = strWithMacVal.getBytes(CHARSET);
        ByteBuffer bb = ByteBuffer.allocate(sb.length + this.lengthPrefixLen);
        String headStr = Integer.toString(sb.length);
        int len = headStr.length();
        byte[] prefixCharByte = this.prefixChar.getBytes(CHARSET);
        if(prefixCharByte.length != 1) {
            log.error("prefixCharByte.length not is 1:" + prefixCharByte.length);
            return;
        }
        
        for(int i=0; i<this.lengthPrefixLen - len; i++) {
            bb.put(prefixCharByte);
        }
        bb.put(headStr.getBytes(CHARSET));
        bb.put(sb);
        if(log.isDebugEnabled()) {
            //不重要,為減少文章長度,忽略
        }
        //這是”動态封包長度“的小改結束
        
        os.write(bb.array());
        os.flush();
    }
    private String showEOL(final String input) {
        //不重要,為減少文章長度,忽略
    }    
}           

更改後,重新編輯打包,和開發提供的Jar包,一起放入$JMETER_HOME/lib/ext目錄裡,同時在user.properties配置tcp.cipher_cn.secKey和jmeter tcp.handler。

到這裡差不多完成了,還差一個,讓JMeter的運作環境可以找到我們的加密庫,參考開發給的運作代碼:

java -Djava.library.path=/dir_path/加密庫檔案 -cp ./xxxx.jar:./ 開發給的測試代碼           

因我的JMeter在linux環境下運作,故更改$JMETER_HOME/bin/jmeter檔案最後一行,如下:

MAC_OPTS="-Djava.library.path=/dir_path/加密庫檔案"
"$JAVA_HOME/bin/java" $ARGS $JVM_ARGS $JMETER_OPTS $MAC_OPTS -jar "$PRGDIR/ApacheJMeter.jar" "$@"           

最後的唠叨

  1. 上述更改,可成功的實作我們的目的,即JMeter調用加密庫更新字段。
  2. 這樣的更改不算難,甚至很簡單,作性能測試,無論是壓測工具,還是輔助測試的代碼,這是達到測試目的的過程而已。
  3. 上述的過程,我們大約需要了解下述幾點:
    • 基礎的java知識點。
    • 對JMeter的TCP Sampler源碼有所了解。
    • 對JMeter的啟動引導有所了解。
    • 和開發的溝通協調。