Netty 刷新挂起字节阈值

Netty 刷新挂起字节阈值,netty,Netty,我在F5工作,一个快乐的网络收养者。我们喜欢耐蒂 我们正在将我们的NETY 3代码迁移到NETY 4的过程中。 为了减少CPU的使用,我们想做的一件事是对写入的消息应用一些刷新策略。例如,将出站消息字节相加,并在达到某个阈值时刷新 对于Netty3,我们有一个处理程序,它做了类似的工作(在队列中聚合消息,稍后再向下游发送消息)。因此,每个出站消息都会自动强制通过该处理程序。作为一个处理程序,我们可以在编码处理程序(出站方向)之后设置它,因此它在继续出站之前对结果字节计数进行汇总 我们可以在Net

我在F5工作,一个快乐的网络收养者。我们喜欢耐蒂

我们正在将我们的NETY 3代码迁移到NETY 4的过程中。 为了减少CPU的使用,我们想做的一件事是对写入的消息应用一些刷新策略。例如,将出站消息字节相加,并在达到某个阈值时刷新

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

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

在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()
的所有调用也会调用这样的“刷新管理器”(不再是处理程序)。这将计算是否刷新的决定,如果是,作为一个not-
非WakeUpRunnable
任务,它将唤醒事件循环,以很快执行所有挂起的
WriteTask
s+刷新任务

但我似乎面临以下问题:
1.如何强制所有对
write()
的调用也调用该刷新管理器。如上所述,在Netty 3中作为处理程序是显而易见的(旧的线程模型,这意味着
channel.write()
的调用线程也将操作下游管道工作)。
2.我无法访问写入缓冲区的字节。现在我必须在
write()
之外调用flush管理器,这意味着不能作为管道上的钩子,而且由于编码只会在将来发生-我无法在
write()
返回时汇总字节数-以决定是否进行flush

因此,这可能会起作用,但仅用于计算挂起的写入消息,而不是总字节数。
除非你有更好的主意

谢谢!继续努力

Shay

基本上你可以一直调用
writeAndFlush(…)
。也就是说,对于netty 4,您不再需要处理程序,因为我们已经为您这样做了。只要调用
write(…)
,然后调用
flush()。这也将确保我们尝试进行一次收集写作,从而为您带来更好的表现。

谢谢Norman。
write()
-
flush()
的分离很聪明,我想利用它。当在
ChannelOutboundBuffer
中聚合10240字节时,我是否可以以某种方式使netty刷新?我知道我不需要像netty 3那样使用
BufferedWriteHandler
来聚合写入的消息(因为
ChannelOutboundBuffer
在核心netty中),但我想我确实需要一些处理程序来对写入的字节进行求和(
write(…)
)并在sum>10240上调用flush。但正如我上面解释的,在我看来,使用处理程序是不可能的。事实上,这是可能的。。。只需通过ChannelOption或ChannelConfig将水印设置为10240,然后在ChannelInboundHandler中使用override channelWritabilityChanged(…),并在通道变为不可写时刷新。感谢Norman,但我认为它可能仍然不起作用-如果
channel.write(…)的调用线程
不是频道的事件循环线程。因为它只会将
WriteTask
推送到通道的事件循环线程并返回。它甚至不会唤醒它来执行
channelWritabilityChanged()
。。。此外,我们已经使用高水位线功能从池中删除连接,直到它再次达到低水位线,从而返回连接。抱歉,似乎我在“它甚至不会唤醒它以执行channelWritabilityChanged()”中犯了一个错误<代码>channelWritabilityChanged(…)
将被设置为事件循环的任务,这也将导致事件循环被唤醒。那很好。不过,
channelwriteabilitychanged(…)
已经被我们系统的其他功能所取代。如果我想计算字节之外的消息数,它将不会被触发(也要根据待处理消息数刷新阈值)。
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);
     }
 }
}