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