我有一个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实例设置的值(下面的延迟值以ms为单位)
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计时器的地方做错了吗?
我该怎么做才能在服务器端准确测量请求延迟,以便它们显示从接收请求到发送答复所花费的时间?
答案 0 :(得分:3)
从服务器(此处为Netty)和客户端(分别为JMeter)的角度来看,延迟的设计完全不同,因此根本无法匹配。
但是,它们可能是客户端的延迟很可能包括服务器的延迟-因此,JMeter端的值将始终更大(您所显示的值只有平均值和百分位-但这对他们来说确实如此) )。
只需查看Jmeter的延迟定义:
延迟。 JMeter测量从发送请求之前到收到第一个响应之后的时间 。 因此, 时间包括组装电池所需的所有处理。 请求以及组装响应的第一部分 ,其中 通常将超过一个字节。协议分析器(例如 Wireshark)测量实际发送/接收字节的时间 接口。 JMeter时间应该更接近 浏览器或其他应用程序客户端体验到的。
看到了吗?
并且服务器对客户端上发生的阶段的了解为零(并计入延迟)。 它也不知道网络路径上发生了什么。
结论:您所看到的完全是预期的。
UPD:有人指出,在边缘情况下,服务器端度量之一超过了JMeter之一。这很有趣,在这里我试图解释这是怎么可能的。
首先免责声明:我不知道您在那里使用的工具包的内在发生了什么(因此,如果我错过了,请不要用力打我)。
尽管如此,在常识推理的帮助下,我可以猜到:
1)问题是您在冲洗后停止计时器。 那里似乎是同步的。
2)因此,服务器端的等待时间测量包括缓冲区的全部刷新。
3)当JMeter测量直到第一个块到达和组装的延迟时。
4)在大多数情况下,服务器的刷新速度足够快,快于网络+ JMeter吞没它的速度。
5)但是在某些极端情况下,服务器或网络只是偶然发现了某些东西,而最后的数据块却迟到了。