想要统计netty网关服务器发送的消息流量和消息频次来监控消息延时或者调用链路或者其他性能问题,正确的埋点方式是在调用write()写方法之后,在ChannelFutureListener的operationComplete方法中进行性能统计。
错误的方式:
正确的方式:
原因是netty里面io操作都是异步的,调用writeAndFlush并不代表消息已经发送到网络上,它仅仅是一个异步的消息发送操作,调用writeAndFlush之后,Netty 会执行一系列操作,最终将消息发送到网络上,整个统计流程中容易忽略的几个地方:
(1)业务ChannelHandler的执行时间。
(2)被异步封装的WriteTask/WriteAndFlushTask在NioEventLoop任务队列中的排队时间。
(3)ByteBuf在ChannelOutboundBuffer队列中的排队时间。
(4)JDK NIO类库将ByteBuffer写入网络的时间。
这里从ctx.write()方法进去一路查看源码就行分析,发现当发送的字节数大于0时会就行ByteBuf的清理工作,NioSocketChannel:
清理ByteBuf的方式是,将发送的字节数与当前ByteBuf可读字节数就行对比,判断当前ByteBuf是否发送完成,如果完成则调用remove()就行清理,否则只更新发送进度,ChannelOutboundBuffer:
其中的remove方法时,最终会调用消息发送 ChannelPromise的trySuccess方法,通知监听消息已经完成发送,相关代码如下( ChannelPromise类):
可以发现,当消息发出后需要一路沿着ctx.write() -> doWrite() -> in.removeByte() -> remove() -> notifyListeners() ,最后触发到我们在writeFuture监听器里面的埋点。