繁体   English   中英

在Netty服务器中Dropwizard指标和JMeter之间的延迟值不一致

[英]Inconsistent latency values between Dropwizard metrics and JMeter in Netty server

我有一台Netty HTTP服务器,正在通过Apache JMeter发送请求进行测试。 我正在使用Dropwizard指标库来测量服务器上的延迟。 我遇到了Dropwizard指标存在问题的情况,该指标显示的延迟值与JMeter不同(平均和第99个百分位数),但有时只是这样。

该处理在使用ThreadPoolExecutor类创建的单独的线程池中进行。 但是,我用sleep语句替换了要在Test.java中完成的实际处理,因此我知道处理需要多长时间。

我的代码如下

LatencyTester.java

public class LatencyTester {

    public static void main(String[] args) throws Exception {
        Executors.newScheduledThreadPool(1);
        displayMetrics.scheduleAtFixedRate(new Metrics(), 10, 10, TimeUnit.SECONDS);
        new NettyServer().run();
    }
}

NettyServer.java

public class NettyServer {

    ThreadPoolExecutor executor;

    public NettyServer() {
    }

    public void run() throws Exception {

        executor = new ThreadPoolExecutor(7,7,100, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            Timer.Context context = Metrics.TIMER.time(); //Start Dropwizard metrics timer
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new HttpServerCodec());
                            p.addLast("aggregator", new HttpObjectAggregator(1048576));
                            p.addLast(new NettyServerHandler(executor, context));
                        }
                    }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(15000).sync();

            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

NettyServerHandler.java

public class NettyServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private Future<ByteBuf> result;
    private Timer.Context cntx;
    private ThreadPoolExecutor threadPool;

    public NettyServerHandler(ThreadPoolExecutor pool, Timer.Context cntx) {
        this.cntx = cntx;
        this.threadPool = pool;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        Test tst = new Test();
        result = threadPool.submit(tst);
        boolean keepAlive = HttpUtil.isKeepAlive(msg);
        FullHttpResponse response = null;
        response = new DefaultFullHttpResponse(HTTP_1_1, OK, result.get());
        String contentType = msg.headers().get(HttpHeaderNames.CONTENT_TYPE);
        if (contentType != null) {
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType);
        }
        response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
        if (!keepAlive) {
            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
        } else {
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            ctx.write(response);
        }
        ctx.flush();
        cntx.stop();  //Stop Dropwizard metrics timer
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

Test.java

public class Test implements Callable<ByteBuf> {

    public Test() {
    }

    @Override
    public ByteBuf call() throws Exception {
        TimeUnit.SECONDS.sleep(5);
        return (Unpooled.copiedBuffer("Done".getBytes()));
    }
}

这是在JMeter上进行一些测试(每次持续5分钟)后获得的一些结果。 服务器和JMeter都在我的笔记本电脑上运行。 下面的服务器线程是指NettyServer.java中为ThreadPoolExecutor实例设置的值(下面的延迟值以毫秒为单位)ServerThreads,JMeterThreads,MetricsAverage,Metrics99thP,JMeterAvg,JMeter99thP
1,1,5018,5167,5012,5031
1,7,33407,35165,33380,35003
5,17,15695,19998,16667,19970-平均相差1秒
50,50,8963,15032,15356,29959-大不同
7,23,11295,14965,16121,20002-大不同

为什么其中一些测试显示与JMeter和Metrics结果不一致? 我在启动和停止Dropwizard Metrics计时器的地方做错了吗?

我该怎么做才能在服务器端准确测量请求延迟,以便它们显示从接收请求到发送答复所花费的时间?

从服务器(此处为Netty)和客户端(分别为JMeter)的角度来看,延迟的设计完全不同,因此根本无法匹配。

不过,它们可能是客户端的延迟很可能包括服务器的延迟-因此,JMeter端的值将始终更大(显示的值只有平均值和百分位-那里的确如此)。

只需查看Jmeter的延迟定义:

延迟时间 JMeter测量从发送请求之前到收到第一个响应之后的延迟。 因此, 该时间包括组装请求以及组装响应的第一部分所需的所有处理 ,通常这将比一个字节长。 协议分析器(例如Wireshark)测量通过接口实际发送/接收字节的时间。 JMeter时间应该更接近浏览器或其他应用程序客户端所经历的时间。

看到?

服务器对客户端上发生的阶段了解为零(并计入延迟)。 它也不知道网络路径上正在发生什么。

结论:您所看到的完全是期望的。

UPD:有人指出,在边缘情况下,服务器端的一项测量超出了JMeter的一项。 这很有趣,在这里我试图解释这是怎么可能的。

首先免责声明 :我不知道您在那里使用的工具包的内在发生了什么(因此,如果我错过了,请不要用力打我)。

尽管在常识推理的帮助下,我可以猜测:

1)问题是您在冲洗后停止计时器。 那里似乎是同步的。

2)因此,服务器端的延迟测量包括缓冲区的全部刷新。

3)当JMeter测量直到第一块到达和组装的延迟。

4)在大多数情况下,服务器的刷新速度足够快,快于网络+ JMeter吞没它的速度。

5)但是在某些情况下,服务器或网络只是偶然发现了某些东西,而最后的数据块却迟到了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM