背景知识
- 如果业务线程调用writeAndFlush()发送消息,会生成WriteAndFlushTask,交由IO线程处理,write操作将消息写入ChannelOutboundBuffer,flush操作将ChannelOutboundBuffer写入socket的发送缓冲区;
- ChannelOutboundBuffer是单向链表,没有容量限制;
- ChannelOutboundBuffer虽然无界,但是可以给它配置一个高水位线和低水位线,当buffer的大小超过高水位线的时候对应channel的isWritable就会变成false,当buffer的大小低于低水位线的时候,isWritable就会变成true。应用发送数据前应该对isWritable进行判断,防止OOM。高水位线和低水位线是字节数,默认高水位是64K,低水位是32K,通过以下方式进行设置:
.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 64 * 1024)
.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)
速率不匹配造成的问题
如下图所示,当业务线程产生消息的速度大于Socket的发送速率时,首先TCP发送缓冲区会被填满,然后后续所有待发送的数据会不断的占用内存加入到ChannelOutboundBuffer中,出现OOM;
速率不匹配解决方案
利用ChannelOutboundBuffer的高低水位特性形成闭环链路:当ChannelOutboundBuffer的容量超过高水位时降低消息产生的速度,当ChannelOutboundBuffer的容量小于低水位时增加消息产生的速度,如下图所示: