Netty 水位详解
来源:互联网 发布:mac古墓丽影9迅雷下载 编辑:程序博客网 时间:2024/05/16 01:21
Netty 写水位
在启动Netty bootstrap的时候可以设置ChannelOption选项,其中ChannelOption中有一项WRITE_BUFFER_HIGH_WATER_MARK选项和WRITE_BUFFER_LOW_WATER_MARK选项,,此配置写缓冲区(OutbounduBuffer)相关,此配置可以帮助用户监控当前写缓冲区的水位状况,ChannelOutboundBuffer本身是无界的,如果水位控制不当的话就会造成占用大量的内存,今天准备结合代码来看看这个配置究竟是有什么作用。
Option配置
ServerAcceptor在获取新的连接之后,就要执行channel的初始化操作,将handler添加到channel的pipeline上,然后使用Bootstrap的option设置到channel上。
public void channelRead(ChannelHandlerContext ctx, Object msg) { final Channel child = (Channel) msg; child.pipeline().addLast(childHandler); setChannelOptions(child, childOptions, logger); //初始化channel选项 for (Entry<AttributeKey<?>, Object> e: childAttrs) { child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue()); } ...}
ChannelConfig默认的水位配置为低水位32K,高水位64K,如果用户没有配置就会使用默认配置。
private volatile WriteBufferWaterMark writeBufferWaterMark = WriteBufferWaterMark.DEFAULT; //设置默认配置
Netty中的channel写数据最终是通过channel的unsafe类实现的,unsafe中有一个ChannelOutboundBuffer属性,每次写操作就是将消息添加到ChannelOutboundBuffer中去,我们看一下ChannelOutboundBuffer的addMessage方法
1、addMessage方法
public void addMessage(Object msg, int size, ChannelPromise promise) { Entry entry = Entry.newInstance(msg, size, total(msg), promise); //把消息封装成一个entry,然后塞到一个单链表中 if (tailEntry == null) { flushedEntry = null; tailEntry = entry; } else { Entry tail = tailEntry; tail.next = entry; tailEntry = entry; } if (unflushedEntry == null) { unflushedEntry = entry; } incrementPendingOutboundBytes(entry.pendingSize, false); //修改当前缓冲区的水位}
addMessage方法就是将消息封装成Entry然后添加到链表当中,然后更新一下当前buffer的水位。
2、incrementPendingOutboundBytes方法
private void incrementPendingOutboundBytes(long size, boolean invokeLater) { if (size == 0) { return; } long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, size); //原子更新一下当前的水位,并获取最新的水位信息 if (newWriteBufferSize > channel.config().getWriteBufferHighWaterMark()) { setUnwritable(invokeLater); //此处判断如果当前的水位超过了我们之前设置的最高水位,就调用setUnwriteable方法 }}
这里是更新了当前buffer的水位,如果当前的水位高于配置的高水位,那么就要调用setUnwriteable方法
setUnwriteable方法
private void setUnwritable(boolean invokeLater) { //此处调用的时候invokeLater是false for (;;) { final int oldValue = unwritable; final int newValue = oldValue | 1; if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) { //原子更新一下当前的状态 if (oldValue == 0 && newValue != 0) { fireChannelWritabilityChanged(invokeLater); //如果之前的状态是可写,现在的状态是不可写,就要调用pipeline上handerd的lWritabilityChanged方法 } break; } }}
高水位的时候就会可以通知到业务handler中的WritabilityChanged方法,并且修改buffer的状态,channel调用isWriteable的时候就会返回false,当前channel处于不可写状态。同样的,低水位应该是缓冲区数据刷到真实channel上的时候用来判断触发事件的。
3、addFlush方法
public void addFlush() { Entry entry = unflushedEntry; if (entry != null) { if (flushedEntry == null) { flushedEntry = entry; } do { flushed ++; if (!entry.promise.setUncancellable()) { int pending = entry.cancel(); decrementPendingOutboundBytes(pending, false, true); //修改当前的水位 } entry = entry.next; } while (entry != null); unflushedEntry = null; }}
addFlush方法就是把当前的entry链表添加到flushedEntry上,然后开始统计flush的数据的大小,并且相应的修改buffer的水位。
4、decrementPendingOutboundBytes方法
private void decrementPendingOutboundBytes(long size, boolean invokeLater, boolean notifyWritability) { if (size == 0) { return; } long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, -size); if (notifyWritability && newWriteBufferSize < channel.config().getWriteBufferLowWaterMark()) { setWritable(invokeLater);//判断当前水位,如果水位小于 }}
此处修改水位的时候就会判断当前水位是否低于WriteBufferLowWaterMarks,如果低于该水位就会设置当前的channel为可写,然后触发可读时间。
小结
水位配置可以帮助我们监控缓冲区的使用情况,在写数据的时候需要判断当前channel是否可以继续向缓冲区写数据(isWriteable)。在之前的工作中出现过没有正确判断,而使用的编码器默认使用的又是堆外内存,导致在不断写入缓存的时候堆外内存超过jvm配置最大值。
- Netty 水位详解
- 高水位(HWM)详解
- Oracle高水位线详解
- oracle高水位线详解
- Oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- oracle 高水位线详解
- protoc-gen-lua 编译、安装、使用教程
- Android Studio连接网易MuMu模拟器
- Is College Education Worth it?
- C语言实验——计算表达式
- 控制程序流程
- Netty 水位详解
- 洛谷P1892团伙
- Java基础之进制算法
- python学习第一步:数据结构与算法
- 一、Java并发编程基础篇(004)脏读
- SpringBoot+Redis+Nginx实现负载均衡以及Session缓存共享
- 1046. 划拳(15) PAT乙级真题
- 例题8-16 不无聊的序列(Non-boring sequences, CERC 2012, UVa1608)
- 人工智能——科技与伦理的权衡?