刷新挂起的字节阈值

时间:2016-05-24 21:38:38

标签: netty

我在F5工作,这是一个快乐的Netty采用者。我们喜欢Netty。 :)

我们正处于将部分Netty 3代码迁移到Netty 4的过程中 为了减少CPU使用率,我们想要做的一件事是在写入消息上应用一些刷新策略。例如,将出站消息字节求和,并在达到某个阈值时进行刷新。

对于Netty 3,我们有一个执行类似工作的处理程序(聚合队列中的消息,稍后发送到下游)。因此,每个出站消息都会被强制执行以通过此处理程序。作为处理程序,我们可以在编码处理程序(出站方向)之后设置它,因此它在继续出站之前总结结果的字节数。

我们可以在Netty 3中使用的处理程序示例(来自BufferedWriteHandler javadoc

public class AutoFlusher extends BufferedWriteHandler {

 private final AtomicLong bufferSize = new AtomicLong();

 @Override
 public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) {
     super.writeRequested(ctx, e);

     ChannelBuffer data = (ChannelBuffer) e.getMessage();
     int newBufferSize = bufferSize.addAndGet(data.readableBytes());

     // Flush the queue if it gets larger than 8KiB.
     if (newBufferSize > 8192) {
         flush();
         bufferSize.set(0);
     }
 }
}

在Netty 4中,我希望:

public class AutoFlusher extends ChannelOutboundHandlerAdapter {
// here, in netty 4, we have the aggregation of written messages 
// into queue inside core netty (ChannelOutboundBuffer), 
// so just extend simple adapter for summing written bytes 
// and flushing when crossing threshold

 private final AtomicLong bufferSize = new AtomicLong();

 @Override
 public void write(ChannelHandlerContext ctx, Object e) {
     super.write(ctx, e);

     ByteBuf data = (ByteBuf) e;
     int newBufferSize = bufferSize.addAndGet(data.readableBytes());

     // Flush the queue if it gets larger than 8KiB.
     if (newBufferSize > 8192) {
         ctx.flush();
         bufferSize.set(0);
     }
 }
}

但是在Netty 4中,我们有了一个新的更严格的线程模型,它不允许我们这样做 - 当调用channel.write(...)的线程不是通道的事件循环线程时。
这是因为当这样的线程调用channel.write(...)时,它会将其WriteTask推入事件循环线程的队列,以便稍后运行。 WriteTask也实现了NonWakeupRunnable,因此调用者线程不会唤醒事件循环线程(我猜是出于性能原因)。因此,如果我使用相同的方法来使用此处理程序 - 它决定是否立即刷新将永远不会执行,或执行得太晚(它在未唤醒的事件循环线程的队列中等待)。

我能想到的唯一能做类似事情的方法是确保(手动)所有对write()的调用也会调用这样的"刷新经理" (不再是处理程序)。这将计算是否刷新的决定,如果是 - 作为非 - NonWakeupRunnable任务,它将唤醒事件循环,以便很快执行所有挂起的WriteTask s +刷新任务。

但后来我似乎面临以下问题:
1.如何强制执行对write()的所有调用也称为刷新管理器。如上所述,在Netty 3中显然是一个处理程序(和旧的线程模型,这意味着channel.write()的调用者线程也将运行下游管道工作)。 2.我无法访问写缓冲区的字节。现在我必须在write()之外调用该flush管理器,这意味着不是管道上的钩子,并且由于编码将仅在将来发生 - 我不能在{{{{{{{ 1}}返回 - 用于决定是否刷新。

这样可以工作,但仅用于计算挂起的写入消息,而不是总字节数 除非你有更好的想法?

谢谢!并保持良好的工作! 谢伊

1 个答案:

答案 0 :(得分:2)

基本上你可以随时拨打writeAndFlush(...)。用netty 4说你不再需要处理程序,因为我们已经为你做了这个。只要你想将它真正写入套接字,就可以调用write(...)然后调用flush()。这也将确保我们尝试进行聚会写作,从而使您获得更好的表现。