当 ChannelOutboundBuffer 已满时写入会发生什么

What happens to writes when ChannelOutboundBuffer is full

我想弄清楚当通道无响应时写入请求会发生什么。例如,当对等方突然断开网络时,就会发生这种情况,而我们永远不会收到 RST。

从阅读文档和达到 , it seems that once the high WriterBufferWaterMark,ChannelOutboundBuffer 将被视为已满,并且:

Channel.isWritable() will start to return false.

来自Channel.isWritable()

Returns true if and only if the I/O thread will perform the requested write operation immediately. Any write requests made when this method returns false are queued until the I/O thread is ready to process the queued write requests.

我最初的问题是:当我们继续写作时会发生什么

Where will the data been queued if Netty channel isWritable return false 声明有一个内部缓冲区,并暗示它是无界的。

问题就变成了,写入请求在的确切位置排队,更重要的是我可以观察这些队列的大小吗?

或者:当Netty/OS检测到连接断开并需要关闭时是否有一些限制?

它仍将在 ChannelOutboundBuffer 中排队。一旦缓冲区已满,您有责任停止写入,并在缓冲区清空后重新开始。您可以通过 ChannelInboundHandler.channelWritabilityChanged(...).

观察到这一点

查看 4.1.37 中 ChannelOutboundBuffer 的源代码,方法 addMessage 总是将传入消息添加到内部链表,无论 isWritable[= 的状态如何21=]。此列表无限增长。

此缓冲区的总字节长度可通过 channel.unsafe().outboundBuffer().totalPendingWriteBytes() 获得。

对于间接值,如果您不想使用 unsafe(),您也可以使用 channel.bytesBeforeWritable(),这将 return 排队字节减去低水位线。

如果我们继续写,会发生什么?

当你调用ChannelHandlerContext#write方法时,netty最终会将你要发送的数据写入一个名为channelOutboundBuffer的队列中。

当由于网络拥塞或Netty客户端负载过高导致网络数据接收速度和处理速度越来越小时,TCP的滑动window不断收缩以减少网络数据的发送直到归零,同时Netty服务器有很多频繁的Write操作,不断的写ChannelOutboundBuffer。

结果,数据发不出去,但是Netty服务端在不停的写数据,会慢慢的爆掉ChannelOutboundBuffer,造成OOM。

所以Netty引入了LOW_WATER_MARKHIGH_WATER_MARK来控制ChannelOutboundBuffer的容量限制,避免ChannelOutboundBuffer无限增长

如何观察这些队列的大小

你可以使用ctx.channel().unsafe().outboundBuffer().totalPendingWriteBytes()查看ChannelOutboundBuffer的总内存使用量