又一次对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的启动引导有所了解。
    • 和开发的沟通协调。
上一篇:Create Volume 操作(Part II) - 每天5分钟玩转 OpenStack(51)


下一篇:《Windows Server 2012活动目录管理实践》——导读