Netty|Netty | 设置高低水位线避免 OOM
Netty 中的高低水位线是什么?
- Netty 中的 Channel 都有一个写缓冲区;
- 这个写缓冲区是 ChannelOutboundBuffer,这是个 Netty 发数据时的仓库,要发送的数据以数据结构 Entry 的形式存在仓库中,Entry 是个链表中的节点;
- Netty 中的高低水位线,对应的就是这个链表中节点的数量范围,用于限制程序的写操作,自己在写程序的时候,需要用相应的代码给予配合,从而避免 OOM,增强写数据时的安全性;
- 相关接口设计:Channel#config -> ChannelConfig#getWriteBufferHighWaterMark;
- 进(读速度) > 出(写速度);
- 上游发送快;
- 自己处理的慢;
- 下游处理的慢;
- 网速慢;
- ChannelOutboundBuffer 相当于 Netty 发送数据的仓库,如果这个仓库存的数据特别多,就会发生 OOM;
- 待写的数据以 ChannelOutboundBuffer.Entry 的数据结构存在 ChannelOutboundBuffer 中,Entry 是个链表中节点的结构,这个由 Entry 链起来的链表本身并没有控制大小,从而导致 OOM;
- 维护 Entry 链表的大小 totalPendingSize,如果 totalPendingSize 大于设定的高水位线 writeBufferWaterMark.high(),就设置标记位 unwritable;
- writeBufferWaterMark 是关联在 Channel 的 ChannelConfig 中的;
- 写暂停时 messagesQueue 中存的待写数据 ToSend 太多,就有可能发生 OOM;
- 判断 queueSize > maxWriteSize 或 delay > maxWriteDelay,如果满足任一条件,设置标志位 unwritable
- 【Netty|Netty | 设置高低水位线避免 OOM】unwritable 是 ChannelOutboundBuffer 中的整型变量,一共 32 位,不同的位标识不同情景下的可写状态,为 0 标识可写,这样的设计考量是为了针对不同的场景做优化和处理,示例如图:
文章图片
unwritable.png
- 设置好高低水位线参数(默认 32 * 1024 ~ 64 * 1024);
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
bootstrap.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
- 在启用流量整形的时候需要考虑设置:
- maxWriteSize(默认 4M);
- maxGlobalWriteSize(默认 400M);
- maxWriteDelay(默认 4s);
- 设置好了参数,如果自己在写代码的时候,没有做判断
channel.isWritable()
的,就跟没设置一样!!! - 示例代码片段:
// 这是对设置的高低水位线参数的尊重,如果设置了高低水位线,这里却不做判断,直接写,就有可能 OOM;
if (ctx.channel().isActive() && ctx.channel().isWritable()) {
ctx.writeAndFlush(responseMessage);
} else {
log.error("message dropped");
}
推荐阅读
- 第6.2章(设置属性)
- 15、IDEA学习系列之其他设置(生成javadoc、缓存和索引的清理等)
- performSelectorOnMainThread:withObject:waitUntilDone:参数设置为NO或YES的区别
- spring|spring boot中设置异步请求默认使用的线程池
- Python绘制小红花
- day|day 28 设置路由表
- flutter设置沉浸式状态栏
- Netty|Netty 源码之 FastThreadLocal
- 谷歌/火狐/Safari浏览器设置手机模式浏览
- 自定义dialog在xml设置宽高失效的解决