Featured image of post 基于Netty的Spring Boot内置Servlet容器的实现(五)

基于Netty的Spring Boot内置Servlet容器的实现(五)

基于Netty的Spring Boot内置Servlet容器的实现(五)

BenchMark 程序编写

BenchMark可以用Jmeter进行,也可以直接编写java Test程序,通过@Befor进行时间计算。
更方便的方法直使JM框架。

JMH简介

JMH是新的microbenchmark(微基准测试)框架(2013年首次发布)。与其他众多框架相比它的特色优势在于,它是由Oracle实现JIT的相同人员开发的。特别是我想提一下Aleksey Shipilev和他优秀的博客文章。JMH可能与最新的Oracle JRE同步,其结果可信度很高。

IDEA的JMH插件

直接使用JMH需要额外编写一些入口方法、增加依赖等,并不是特别方便,而IDEA有插件支持JMH。打开Files-Settings,找到Plugins选项卡,安装JMH Plugin插件,安装后重启如下:

编写BenchMark方法

安装JMH Plugin插件之后无需编写入口方法、增加依赖,可以直接关注具体的测试。
编写一个简单例子,测试我们容器的测试用例吞吐量:

@BenchmarkMode(Mode.Throughput)
public class NettyServletBenchmark {
    @Benchmark
    @Warmup(iterations = 10)
    @Measurement(iterations = 20)
    public void plaintext() {
        getUrl("http://localhost:9999/netty/plaintext", false);
    }

    @Benchmark
    @Warmup(iterations = 10)
    @Measurement(iterations = 20)
    public void json() {
        getUrl("http://localhost:9999/netty/json?msg=1", false);
    }

    private String getUrl(String url, boolean read) {
        BufferedReader br = null;
        InputStream is = null;
        StringBuilder sbuf = new StringBuilder();
        try {
            URL reqURL = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) reqURL.openConnection(); // 进行连接,但是实际上getrequest要在下一句的connection.getInputStream() 函数中才会真正发到服务器
            connection.setDoOutput(false);
            connection.setUseCaches(false);
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(200);
            connection.setDoInput(true);
            connection.connect();
            if (read) {
                br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    sbuf.append(line).append("\n");
                }
            } else {
                is = connection.getInputStream();

            }
        } catch (IOException e) {
            System.out.println("连接服务器'" + url + "'时发生错误:" + e.getMessage());
        } finally {
            try {
                if (null != br) {
                    br.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sbuf.toString();
    }
}

其中@BenchmarkMode(Mode.Throughput)表示测试吞吐量,即一秒内可以跑多少次测试方法。其他的测试模式如下:

名称描述
Mode.Throughput计算一个时间单位内操作数量
Mode.AverageTime计算平均运行时间
Mode.SampleTime计算一个方法的运行时间(包括百分位)
Mode.SingleShotTime方法仅运行一次(用于冷测试模式)。或者特定批量大小的迭代多次运行;这种情况下JMH将计算批处理运行时间(一次批处理所有调用的总时间)
这些模式的任意组合可以指定这些模式的任意组合——该测试运行多次(取决于请求模式的数量)
Mode.All所有模式依次运行

接下来是具体的测试方法:

@Benchmark
@Warmup(iterations = 10)
@Measurement(iterations = 20)
public void plaintext() {
    getUrl("http://localhost:9999/netty/plaintext", false);
}

其中@Benchmark注解表示当前方法是需要JMH执行测试的方法,@Warmup(iterations = 10)表示每次正式测试前,先跑10次进行热身(不参与测试结果的计算),@Measurement(iterations = 20)表示每次正式测试执行20次方法。

执行测试

执行方法很简单,点击菜单Run-Run...,弹出窗中选择当前类,即可:


等测试完毕,就会打印出测试结果:

Result "io.gitlab.leibnizhu.sbnetty.benchmark.NettyServletBenchmark.plaintext":
  6508.938 ±(99.9%) 189.498 ops/s [Average]
  (min, avg, max) = (157.637, 6508.938, 7098.929), stdev = 802.346
  CI (99.9%): [6319.440, 6698.436] (assumes normal distribution)
Benchmark                         Mode  Cnt     Score     Error  Units
NettyServletBenchmark.json       thrpt  200  6756.677 ± 182.976  ops/s
NettyServletBenchmark.plaintext  thrpt  200  6508.938 ± 189.498  ops/s

可以看到IDEA对该类两个带有@Benchmark注解的方法分别进行了测试,测试结果分别是6.76kQps和6.51kQps(平均值)。

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy