Calculation of written and read bytes in netty app

2019-09-09 22:58发布

I need to track individual client's connections (written, read bytes and speed(bytes per second)) in my simple http server netty app. As I understand, to do this, I have to use ChannelTrafficShapingHandler. What methods must be overriden and how can I do these calculations?

My ChannelInitializer:

public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("codec", new HttpServerCodec())
                .addLast("traffic", new TrafficShapingHandler(AbstractTrafficShapingHandler.DEFAULT_CHECK_INTERVAL))
                .addLast("handler", new HttpServerHandler());
    }
}

My SimpleChannelInboundHandler:

public class HttpServerHandler extends SimpleChannelInboundHandler<HttpRequest> {

    private static DefaultChannelGroup activeChannels = new DefaultChannelGroup("netty-receiver", ImmediateEventExecutor.INSTANCE);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        activeChannels.add(ctx.channel());
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
        if (is100ContinueExpected(req)) {
            ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
        }

        String uri = req.getUri().toLowerCase();

        Controller controller = ControllerFactory.getController(uri);

        FullHttpResponse response = controller.getResponse();

        if (controller instanceof HelloController) {
            ctx.executor().schedule(() -> ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE), 3, TimeUnit.SECONDS);
        } else {
            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
        }
    }

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

    public static long getConnectionsQuantity() {
        return activeChannels.size();
    }

}

1条回答
欢心
2楼-- · 2019-09-09 23:19

@TMS, in order to be able to get statistics, you first need to choose the level of the statistics: per channel, globally or both.

  • ChannelTrafficShapingHandler: you must create one item per channel (as you did in your pipeline), it is linked to one and only one channel. The statistics are only per channel, not global.

  • GlobalTrafficShapingHandler: you must create it before any channel and assign it to each channel as you did but reusing the same object each time (no reallocation). The statistics are only global, not per channel.

  • GlobalChannelTrafficShapingHandler: you must create it before (as for GlobalTSH) and assign it to each channel (no reallocation). The statistics are global and per channel.

Once you decided which one is for you, there are mainly 2 ways to get statistics:

  1. Through pipeline access: getting access to the handler and then:
    • using trafficCounter() method to access the TrafficCounter object:
      • for the channel (ChannelTSH only)
      • for the global vision (GlobalTSH or GlobalChannelTSH).
    • using channelTrafficCounters() to access all TrafficCounters for all active channels (GlobalChannelTSH only)
  2. Through extending the base class (one of ChannelTSH, GlobalTSH or GlobalChannelTSH) and specifically the protected void doAccounting(TrafficCounter counter) method.

You can look at one example made for Netty but not imported finally in the main stream that shows how to extend it and using it: see here and in particular how to extend GlobalChannelTSH or how to include it in your pipeline here.

Of course, you could have a look at the API that explain partially this too.

Finally, if you want to have both statistics for channel and globally, you have the choice to:

  • either use GlobalChannelTSH (only one reused all the time), but you have to check yourself which channel is attached to which TrafficCounter (using name()) (GlobalChannelTSH is mainly intend to limit the memory impact on traffic shapping when doing it on both levels, per channel and globally, but when used only for statistics, probably not the best choice);
  • either use both ChannelTSH (so direct access to the TrafficCounter per Channel) and GlobalTSH (for the global TrafficCounter only).
查看更多
登录 后发表回答