图解:Netty的TCP_NODELAY选项

Posted 40岁资深老架构师尼恩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图解:Netty的TCP_NODELAY选项相关的知识,希望对你有一定的参考价值。

Netty的TCP_NODELAY选项

来自社群小伙伴的交流

总目录 博客园版 为您奉上更多の珍贵的学习资源

有关本文的 脚本 和 代码,可以来 尼恩 发起的Java 高并发 疯狂创客圈 社群 交流和获取。

Netty的TCP选项的配置

DefaultSocketChannelConfig




    @SuppressWarnings("unchecked")
    @Override
    public <T> T getOption(ChannelOption<T> option) 
        if (option == SO_RCVBUF) 
            return (T) Integer.valueOf(getReceiveBufferSize());
        
        if (option == SO_SNDBUF) 
            return (T) Integer.valueOf(getSendBufferSize());
        
        if (option == TCP_NODELAY) 
            return (T) Boolean.valueOf(isTcpNoDelay());
        
        if (option == SO_KEEPALIVE) 
            return (T) Boolean.valueOf(isKeepAlive());
        
        if (option == SO_REUSEADDR) 
            return (T) Boolean.valueOf(isReuseAddress());
        
        if (option == SO_LINGER) 
            return (T) Integer.valueOf(getSoLinger());
        
        if (option == IP_TOS) 
            return (T) Integer.valueOf(getTrafficClass());
        
        if (option == ALLOW_HALF_CLOSURE) 
            return (T) Boolean.valueOf(isAllowHalfClosure());
        

        return super.getOption(option);
    

    @Override
    public <T> boolean setOption(ChannelOption<T> option, T value) 
        validate(option, value);

        if (option == SO_RCVBUF) 
            setReceiveBufferSize((Integer) value);
         else if (option == SO_SNDBUF) 
            setSendBufferSize((Integer) value);
         else if (option == TCP_NODELAY) 
            setTcpNoDelay((Boolean) value);
         else if (option == SO_KEEPALIVE) 
            setKeepAlive((Boolean) value);
         else if (option == SO_REUSEADDR) 
            setReuseAddress((Boolean) value);
         else if (option == SO_LINGER) 
            setSoLinger((Integer) value);
         else if (option == IP_TOS) 
            setTrafficClass((Integer) value);
         else if (option == ALLOW_HALF_CLOSURE) 
            setAllowHalfClosure((Boolean) value);
         else 
            return super.setOption(option, value);
        

        return true;
    

Netty的TCP选项

关于 本文的技术问题, 请来尼恩 发起的Java 高并发 疯狂创客圈 社群交流 ,

Option.TCP_NODELAY

TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。

为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。

TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,

同时,对方接收到数据,也需要发送ACK表示确认。

为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。

MTU:一个网络包的最大长度,以太网中一般为 1500 字节;
MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度; 最大 1460

Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。

所谓“小段”,指的是小于MSS尺寸的数据块,

所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

举个例子,比如之前的blog中的实验,

一开始client端调用socket的write操作将一个int型数据(称为A块)写入到网络中,由于此时连接是空闲的(也就是说还没有未被确认的小段),因此这个int型数据会被马上发送到server端,

接着,client端又调用write操作写入‘/r/n’(简称B块),这个时候,A块的ACK没有返回,

所以可以认为已经存在了一个未被确认的小段,所以B块没有立即被发送,一直等待A块的ACK收到(大概40ms之后),B块才被发送。

整个过程如图所示:

这里还隐藏了一个问题,就是A块数据的ACK为什么40ms之后才收到?

这是因为TCP/IP中不仅仅有nagle算法,还有一个 ACK延迟机制 。

当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为t),

它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。

在我之前的时间中,t大概就是40ms。这就解释了为什么’/r/n’(B块)总是在A块之后40ms才发出。

如果你觉着nagle算法太捣乱了,那么可以通过设置TCP_NODELAY将其禁用 。

当然,更合理的方案还是应该使用一次大数据的写操作,而不是多次小数据的写操作。

关于 本文的技术问题, 请来尼恩 发起的Java 高并发 疯狂创客圈 社群交流 ,

Option.SO_RCVBUF

Option(Option.SO_RCVBUF, XX),

recv_buf 不会预先分配内存, 只是个接收缓冲区size的最大限制,

不建议设置rcv_buf, linux内核会对每一个连接做动态的 调整, 一般情况下足够智能, 如果设置死了, 就失去了这个特性, 尤其是大量长连接的应用,

Option.SO_SNDBUF

Option(Option.SO_SNDBUF, XX),

send_buf 不会预先分配内存, 只是个发送缓冲区size的最大限制,

不建议设置send_buf , linux内核会对每一个连接做动态的 调整, 一般情况下足够智能, 如果设置死了, 就失去了这个特性, 尤其是大量长连接的应用,

Option.RCVBUF_ALLOCATOR

不是TCP协议选项

关于 本文的技术问题, 请来尼恩 发起的Java 高并发 疯狂创客圈 社群交流 ,

参考文献

1.疯狂创客圈 JAVA 高并发 总目录

ThreadLocal(史上最全)

  1. 3000页《尼恩 Java 面试宝典 》的 35个面试专题
  2. 40岁老架构师 尼恩 练就的 价值10W的架构师知识图谱

4、40岁老架构师 尼恩 练就的 架构师哲学

5、40岁老架构师 尼恩 练就的 3高架构知识宇宙

https://blog.csdn.net/qq_22310551/article/details/124431034

https://blog.csdn.net/u013887008/article/details/104361380

https://article.itxueyuan.com/e196bP

https://blog.csdn.net/xiaolifeidaofirst/article/details/125218511

https://blog.csdn.net/small_engineer/article/details/124190620

https://learnku.com/articles/47193

https://www.cnblogs.com/xiaolincoding/p/12995358.html

https://blog.csdn.net/sinat_20184565/article/details/104828782

https://www.cnblogs.com/qhdziyan/p/16044974.html

http://blog.csdn.net/historyasamirror/article/details/6423235

以上是关于图解:Netty的TCP_NODELAY选项的主要内容,如果未能解决你的问题,请参考以下文章

nginx优化之keepalive

nginx优化之keepalive

nginx优化笔记(keepalivehttps等)

nginx优化——包括httpskeepalive等

nginx优化——包括httpskeepalive等

.NET WebSockets 和 TCP_NODELAY