gsrunion
gsrunion

Reputation: 419

Concurrently handling multiple requests from a single client with Netty

I am tweaking the basic Netty Discard server example in an effort to understand how Netty deals with concurrent requests from the same connected client. I have the following handler....

private static class Handler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext arg0, String arg1) throws Exception {
        System.out.println("received " + arg1);
        Thread.sleep(10000);
        System.out.println("woke up");
    }
}

And the server stood up as follows....

public static void run() throws Exception {
    EventLoopGroup bossGroup = new NioEventLoopGroup(1); // (1)
    EventLoopGroup workerGroup = new NioEventLoopGroup(3);
    try {
        ServerBootstrap b = new ServerBootstrap(); // (2)


        b.group(bossGroup, workerGroup)
         .channel(NioServerSocketChannel.class) // (3)
         .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
             @Override
             public void initChannel(SocketChannel ch) throws Exception {
                 ch.pipeline().addLast(new StringDecoder());
                 ch.pipeline().addLast(new Handler());
             }
         })
         .option(ChannelOption.SO_BACKLOG, 128)          // (5)
         .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

        // Bind and start to accept incoming connections.
        ChannelFuture f = b.bind(4744).sync(); // (7)

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

With the server ran as such...

public static void main(String[] args) {
    System.out.println("heere");
    Executors.newSingleThreadExecutor().execute(() -> {
        try {
            run();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    });
} here

My goal here is to see the Handler ran with multiple threads, indicated by intertwined 'receive' and 'woke up' traffic. I was under the impression that the worker group are the threads that service the request, and I have 3 assigned to it, but I am not seeing the concurrency I expect. What am I doing wrong.

Upvotes: 1

Views: 1766

Answers (2)

Laurent Caillette
Laurent Caillette

Reputation: 1351

Your Handler is blocking the calling thread, which might be OK to simulate a heavy workload (regardless of CPU usage) but Netty is not supposed to run long-lasting tasks in its EventLoop because they prevent reuse of the threads that should process inbound messages. Your run() method is blocking the caller (with f.channel().closeFuture().sync()). The caller is the main() method in a SingleThreadExecutor. So you are running one server at a time, which accepts one connection at a time.

@Apolozeus' answer is correct in the sense that reducing the sleep delay gets you closer to the behavior that Netty is designed to support.

You want to experiment with concurrent connections from the same client. Unless you write specific code, it doesn't matter if the same client (same remot IP address from server's point of view) or different ones are connecting.

Your code is very weird in the sense that you run a server several times. This shows you that f.channel().closeFuture().sync() is a blocking call. You could get a behavior closer to a real application with a single server offloading the "sleep task" to another executor. The "sleep task" should also send some response to the client and close the Channel.

Upvotes: 1

sayboras
sayboras

Reputation: 5165

I just quickly ran your code, and see that there is nothing wrong. It might related on order of running and timing as well. So I would recommend you to change our handler as as per below. Basically, thread name is added and sleep time is reduced to 1 second. Please find below sample output, I can see different requests are handled concurrently by all 3 threads.

protected void channelRead0(ChannelHandlerContext arg0, String arg1) throws Exception {
    System.out.println("received " + Thread.currentThread().getName() );
    Thread.sleep(1000);
    System.out.println("woke up " + Thread.currentThread().getName());
}

Output

...
received nioEventLoopGroup-3-1
received nioEventLoopGroup-3-2
woke up nioEventLoopGroup-3-1
received nioEventLoopGroup-3-1
woke up nioEventLoopGroup-3-2
received nioEventLoopGroup-3-2
woke up nioEventLoopGroup-3-1
received nioEventLoopGroup-3-1
woke up nioEventLoopGroup-3-2
received nioEventLoopGroup-3-2
received nioEventLoopGroup-3-3
...

Upvotes: 1

Related Questions