Netty源码解析 -- ChannelOutboundBuffer实现与Flush过程

本文深入探讨Netty的ChannelOutboundBuffer实现和Flush过程。内容涵盖ChannelOutboundBuffer如何缓存数据、Flush操作的细节,以及如何避免内存溢出问题。同时介绍了ChannelHandlerContext#flush和#write的交互,以及相关的优化策略如FlushConsolidationHandler。
摘要由CSDN通过智能技术生成

前面文章说了,ChannelHandlerContext#write只是将数据缓存到ChannelOutboundBuffer,等到ChannelHandlerContext#flush时,再将ChannelOutboundBuffer缓存的数据写到Channel中。

本文分享Netty中ChannelOutboundBuffer的实现以及Flush过程。

源码分析基于Netty 4.1

每个Channel的AbstractUnsafe#outboundBuffer 都维护了一个ChannelOutboundBuffer。
ChannelOutboundBuffer,出站数据缓冲区,负责缓存ChannelHandlerContext#write的数据。通过链表管理数据,链表节点为内部类Entry。

关键字段如下

Entry tailEntry;        // 链表最后一个节点,新增的节点添加其后。
Entry unflushedEntry;    // 链表中第一个未刷新的节点
Entry flushedEntry;        // 链表中第一个已刷新但数据未写入的节点
int flushed;            // 已刷新但数据未写入的节点数

ChannelHandlerContext#flush操作前,需要先刷新一遍待处理的节点(主要是统计本次ChannelHandlerContext#flush操作可以写入多少个节点数据),从unflushedEntry开始。刷新完成后使用flushedEntry标志第一个待写入的节点,flushed为待写入节点数。

前面分享Netty读写过程的文章说过,AbstractUnsafe#write处理写操作时,会调用ChannelOutboundBuffer#addMessage将数据缓存起来

public void addMessage(Object msg, int size, ChannelPromise promise) {
    // #1
    Entry entry = Entry.newInstance(msg, size, total(msg), promise);
    if (tailEntry == null) {
        flushedEntry = null;
    } else {
        Entry tail = tailEntry;
        tail.next = entry;
    }
    tailEntry = entry;
    if (unflushedEntry == null) {
        unflushedEntry = entry;
    }

    incrementPendingOutboundBytes(entry.pendingSize, false);
}

#1 构建一个Entry,注意,这里使用了对象池RECYCLER,后面有文章详细解析。
主要是更新tailEntry和unflushedEntry
#2 如果当前缓存数量超过阀值WriteBufferWaterMark#high,更新unwritable标志为true,并触发pipeline.fireChannelWritabilityChanged()方法。
由于ChannelOutboundBuffer链表没有大小限制,不断累积数据可能导致 OOM,
为了避免这个问题,我们可以在unwritable标志为true时,不再继续缓存数据。
Netty只会更新unwritable标志,并不阻止数据缓存,我们可以根据需要实现该功能。示例如下

if (ctx.channel().isActive() && ctx.channel().isWritable()) {
    ctx.writeAndFlush(responseMessage);
} else {
    ...
}

addFlush方法负责刷新节点(ChannelHandlerContext#flush操作前调用该方法统计可写入节点数据数)

public void addFlush() {
    // #1
    Entry entry = unflushedEntry;
    if (entry != null) {
        // #2
        if (flushedEntry == null) {
            // there is no flushedEntry yet, so start w
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值