0

I have a client that needs to send alot of small messages to a server (< 8k each messages), now a single thread can push about 1.2 million of messages one after the other without delay in between the reception of those messages.

How would I configure my netty client to "buffer" the write so it flushes automatically at a given buffer size and doesn't create me OOM errors ?

As a simple example, let's say I want to send the content of a file, line by line to simulate the reception of such messages.

    EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<Channel>() {

                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(new StringEncoder());
                }
            });

            // Start the connection attempt.
            Channel ch = b.connect("localhost", 6000).sync().channel();

            ChannelFuture lastWriteFuture = null;
            BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(new File(
                    "data.txt"))));
            int i = 0;
            while (true) {
                // This simulates the incoming data
                String line = in.readLine();
                if (line == null) {
                    break;
                }

                lastWriteFuture = ch.write(line + '\n');
                // TODO : Investigate why we need this, otherwise it throws OOM errors...
                if (i++ % 10000 == 0) {
                    ch.flush();
                    lastWriteFuture.awaitUninterruptibly();
                }
            }

            // This part is here only because it's a simulation, there is no notion of "end of data" in our normal process, it's continuous send of data.
            ch.flush();
            // Wait until all messages are flushed before closing the channel.
            if (lastWriteFuture != null) {
                lastWriteFuture.sync();
            }
        } finally {
            // The connection is closed automatically on shutdown.
            group.shutdownGracefully();
        }

What I'm trying to figure out, is how can I make continuous write without the need to flush at every X messages ?

I've seen Norman's Maurer talk about VoidChannelPromise, however that can't be used here as I'll eventually need SslHandler in the pipeline as well.

Do I need and how to implement some throttling ?

Also, Netty 3 had BufferedWriteHandler which doesn't seem to exist anymore in netty 4.0, am I overlooking some option I could set to "enable" buffering ?

Any example to achieve this ?

Thanks,

DarkRift
  • 224
  • 2
  • 11
  • Does this answer help? http://stackoverflow.com/questions/19720956/get-oom-exception-when-sending-message-with-a-high-speed-with-netty/19721250#19721250 – trustin Mar 26 '15 at 03:21
  • This only answers half the problem if my assumptions are correct. The problem is still that the handler is in another thread and I have to block the main thread for some small period (either flush or until channel is writable again). I can definitely check for isWritable() in the main thread on the channel (which I found after posting this) and then I can to writeAndFlush(). However, it seems that I need to sync() on the returned future or I still end up with OOME or GC overhead exception. – DarkRift Mar 26 '15 at 10:40
  • Also, I feel that there are still room for improvments with this approach (which is where is my guess). My assumption is that future.sync() will wait until the flush message is executed, but can the channel become writable before flush is actually executed ? If the answer is no, then I guess writeAndFlush().sync() when detecting isWritable() == false is the best way to go. @trustin am I wrong here ? – DarkRift Mar 26 '15 at 10:46
  • You'll be notified when `isWritable()` becomes `true` via `channelWritabilityChanged()` event handler method. You can resume writing there. No need to call `.sync()`. – trustin Mar 27 '15 at 08:30
  • Then how do you "block" or slow down the main thread that sends data to the queue which is then handled by another thread ? normal synchronization mechanism ? Do you have an example to demonstrate that ? – DarkRift Mar 27 '15 at 18:53
  • You can use the usual signalling mechanism (e.g. `Object.wait()` and `Object.notify()`). Alternatively, you can do everything in the I/O thread by making your application driven by some finite state machine. – trustin Apr 02 '15 at 03:10

0 Answers0