我在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}}返回 - 用于决定是否刷新。
这样可以工作,但仅用于计算挂起的写入消息,而不是总字节数 除非你有更好的想法?
谢谢!并保持良好的工作! 谢伊
答案 0 :(得分:2)
基本上你可以随时拨打writeAndFlush(...)
。用netty 4说你不再需要处理程序,因为我们已经为你做了这个。只要你想将它真正写入套接字,就可以调用write(...)
然后调用flush()
。这也将确保我们尝试进行聚会写作,从而使您获得更好的表现。