了解 netty 通道缓冲区和水印
Posted
技术标签:
【中文标题】了解 netty 通道缓冲区和水印【英文标题】:Understanding netty channel buffers and watermarks 【发布时间】:2017-08-02 16:03:10 【问题描述】:我正在尝试了解 netty 缓冲区和水印。
作为一个测试用例,我有一个写入客户端的 netty 服务器,客户端被阻塞(每次读取之间基本上有 10 秒的睡眠)
在正常 I/O 下,如果接收方被阻塞,TCP 发送方将受到限制(由于流量控制,发送速度变慢),这里不是这种情况。发件人似乎在每次发送时都在不断写入和刷新数据。这些数据写在哪里? netty 的 flush() 中也会有流控制吗? 见:https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_control
它是否正在写入操作系统或 TCP 缓冲区,netty 通道是否也有内部缓冲区?如果可以,我该如何配置?
我跟踪 bytesBeforeUnwritable 但它们似乎没有减少
什么是默认的高水位线和低水位线?我没有在我的应用程序中设置任何东西。有什么方法可以代替它吗?代码如下:
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg)
if (server2OutboundChannel.isActive())
if(server2OutboundChannel.isWritable())
server2OutboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener()
@Override
public void operationComplete(ChannelFuture future)
if (future.isSuccess())
// was able to flush out data, start to read the next chunk
//System.out.println(server2OutboundChannel.bytesBeforeUnwritable());
ctx.channel().read();
else
future.channel().close();
);
else
System.out.println("Channel is no longer writeable");
System.out.println(server2OutboundChannel.bytesBeforeUnwritable());
System.out.println(server2OutboundChannel.bytesBeforeWritable());
使用端到端源代码重新创建的详细步骤:
克隆https://github.com/nipunarora/nettyDuplicator。
具体来说,代理代码在这里:
https://github.com/nipunarora/nettyDuplicator/tree/master/src/main/java/org/columbia/parikshan/proxy
编译和构建:
mvn package
启动服务器
sh scripts/Server.sh 3380
启动网络代理
sh scripts/nettyProxy.sh -l 0.0.0.0:3379 -o 127.0.0.1:3380
启动客户端
sh scripts/Client.sh 127.0.0.1 3379
在客户端发送“hello”作为标准输入
netty 会在一段时间后阻止发送,并且 bytesTillUnwritable 不会减少。
【问题讨论】:
【参考方案1】:这些数据写在哪里? netty的flush()中也会有流控吗?
数据转到ChannelOutboundBuffer
。没有像 tcp 这样的流量控制。数据将保存在ChannelOutboundBuffer
中,直到 tcp 的发送缓冲区中有空间。
它正在被写入操作系统或 TCP 缓冲区,netty 通道是否也有内部缓冲区?如果可以,我该如何配置?
Netty 有ChannelOutboundBuffer
在发送到操作系统缓冲区之前保存数据。你可以像下面这样配置它。
Bootstrap bootstrap = new Bootstrap();
bootstrap.option(ChannelOption.SO_RCVBUF, soRcvBufSize);
bootstrap.option(ChannelOption.SO_SNDBUF, soSndBufSize);
bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, writeBufferHighWaterMark);
我跟踪 bytesBeforeUnwritable 但它们似乎没有减少
我写了一个sample code 那个服务器写到一个被阻塞的客户端
您的代理的AUTO_READ
是假的。 NettyProxyFrontendHandler#channelRead
只会在 ctx.channel().read()
(未来的监听器)被调用时被调用。侦听器将在writeAndFlush
完成后调用。 writeAndFlush
将生成一个任务,当 msg 写入操作系统的缓冲区时,该任务将完成。如果操作系统的缓冲区被填满,任务将被阻塞。 netty 的缓冲区不可能变成不可写的,它始终是可写的。
什么是默认的高水位线和低水位线?我没有在我的应用程序中设置任何东西。有什么办法可以代替它吗?
您可以查看DefaultChannelConfig
-> WriteBufferWaterMark.DEFAULT
中的默认水印。当ChannelOutboundBuffer
中的数据>高水位时,isWritable返回false,
/**
* Returns @code true if and only if the I/O thread will perform the
* requested write operation immediately. Any write requests made when
* this method returns @code false are queued until the I/O thread is
* ready to process the queued write requests.
*/
boolean isWritable();
【讨论】:
@louxiu- 如果数据被保存在出站缓冲区中,即使使用 writeandflush() 函数也不应该减少不可写之前的字节数? 是的,应该会减少。您的服务器写入速度有多快?当客户端操作系统的接收缓冲区已满且服务器操作系统的发送缓冲区已满时,bytesBeforeUnwritable 将减少。也许你应该完全阻止你的客户。 我在运行测试用例后通过完全阻止服务器中的接收进行了检查。 netty 基本上用作客户端和服务器之间的代理。客户端不断循环发送消息,消息也与计数器一起打印到 System.out。客户端最终停止发送更多消息。代理不断转发这些消息,“never”变得不可写,bytebeforeunwritable 也没有减少。 我怀疑你所说的只有当你在写而不是在写和冲洗时才是真的?因为我的理解很简单,“写入”只写入通道缓冲区而不一定写入操作系统缓冲区。?我更新了代码以显示我用于测试的打印输出。 在 gist 上写一个示例代码。 gist.github.com/louxiu/675027ae7563403dd8c71e4ae8ec095d以上是关于了解 netty 通道缓冲区和水印的主要内容,如果未能解决你的问题,请参考以下文章