TCP系列34—窗口管理&流控—8、缓存自动调整
一、概述
我们之前介绍过一种具有大的带宽时延乘积(band-delay product、BDP)的网络,这种网络称为长肥网络(LongFatNetwork,即LFN)。我们想象一种简单的场景,假设发送端的发送窗口为5000bytes,网络的RTT为200ms,那么每秒的最大速率则为5000*(1000/200)=25000bytes/s,这大约为24kb/s,可以看到这个速率是非常低的,这就是TCP发送窗口对于发送速率的限制,实际的window size应该至少为带宽时延积才能高效的利用网络传输能力。因此对于长肥网络需要扩大TCP的window size,我们之前就已经介绍过RFC1323提高的高性能TCP扩展选项WSOPT,这允许了TCP使用更大的window size(大约是1GB)。但是我们在连接建立初始化的时候很难确切的知道这个这个网络的带宽时延积,这就需要对于window size的一种自动调整(auto-tuning)算法,对于长肥网络能自动抬升TCP的接收缓存,进而增大window size。有时这种接收缓存自动调整技术也称为Dynamic Right-Sizing(DRS)。
二、linux下相关的几个配置参数简单介绍
net.ipv4.tcp_moderate_rcvbuf
这个参数设置为非0,且用户没有通过SO_RCVBUF设置socket对应的接收缓存的时候,那么TCP就会自动调整接收缓存。但是调整的接收窗口最大值不会超过tcp_rmem[2]。这对于长时延高传输速率的网络来说,可以大幅提高接收窗口提高传输速率。
net.core.wmem_max和net.core.rmem_max
这两个参数分别决定了通过SO_SNDBUF和SO_RCVBUF这两个SOCKET选项能设置的最大的发送缓存值和接收缓存值,另外通过SO_SNDBUF和SO_RCVBUF设置的时候还有两个下限,在ubuntu16.04上分别是4608和2304,,还记前前面实例中我们介绍过通过这两个选项设置接收缓存的时候实际上内核会将设置的值先乘2吧,假如通过SO_RCVBUF设置接收缓存为3500,那么内核会max(min(3500*2,rmem_max),2304)=7000,最终将接收缓存设置为7000。
net.ipv4.tcp_adv_win_scale
上面举例中的7000bytes缓存会分为两部分,一部分用于接收窗口的称为内核缓存,这个对应实际的接收的有效TCP数据,另外一部分用于存储这些TCP数据的辅助结构(skb),这部分称为应用缓存,这个是linux的man page的称呼,应用缓存这个称呼好像不是很合适(linux的man page也会有错误的,比如对于tcp_retries2参数的解释就是错的,对于这个应用缓存和内核缓存的解释实在不想吐槽了)。这两部分的比例可以通过tcp_adv_win_scale设置。如果tcp_adv_win_scale>0,则应用缓存占bytes/2^tcp_adv_win_scale,如果这个参数小于0,则应用缓存占bytes- bytes/2^(-tcp_adv_win_scale)。比如设置为tcp_adv_win_scale为2的时候,用于window size的缓存则为7000*(1-1/2^2)=5250bytes。
net.core.wmem_default和net.core.rmem_default
这两个参数指定了传输层协议的默认发送缓存和接收缓存
net.ipv4.tcp_wmem和net.ipv4.tcp_rmem
其中tcp_wmem这个值是由三个整数组成,三个整数分别是min, default, max。min是给每个socket的最小接收缓存的保证值,即使在有内存压力的情况下,如果当前已经真实分配的接收缓存低于min,分配的时候仍然可以分配出内存。default则会覆盖wmem_default,wmem_default指定的是传输层协议的发送缓存默认值,default进一步指定了TCP协议下发送缓存的默认值。比如UDP没有指定自己的发送缓存的默认值那么就会使用wmem_default作为默认值。max则指定了发送缓存的最大值。tcp_rmem这个参数与tcp_wmem类似。
三、wireshark示例
1、缓存自动调整这块在实现上相对复杂一些,这里仅给出一个示例,不再仔细说明调整过程。如下面两张图所示,client端开始每隔5ms写入40bytes的数据,连续写入三次,接着client端在连续写入5次4096bytes的数据,每次写入之间不停顿。可以看到在开始的每次写入40bytes的数据的时候server端的window size一直为2088,在连续大量写入5次4096bytes的数据后,server端开始缓慢增加window size直到最后第49个数据包window size变为43848。
补充说明:
1、http://kb.pert.geant.net/PERTKB/TCPBufferAutoTuning
2、http://patchwork.ozlabs.org/patch/276802/mbox/
3、具体的接收缓存调整算法已经超过本文的介绍范围了,可以参考tcp_rcv_space_adjust、tcp_rcv_rtt_update、tcp_clamp_window、tcp_grow_window
TCP系列34—窗口管理&流控—8、缓存自动调整的更多相关文章
- TCP系列27—窗口管理&流控—1、概述
在前面的内容中我们依次介绍了TCP的连接建立和终止过程和TCP的各种重传方式.接着我们在这部分首先关注交互式应用TCP连接相关内容如延迟ACK.Nagle算法.Cork算法等,接着我们引入流控机制(f ...
- TCP系列31—窗口管理&流控—5、TCP流控与滑窗
一.TCP流控 之前我们介绍过TCP是基于窗口的流量控制,在TCP的发送端会维持一个发送窗口,我们假设发送窗口的大小为N比特,网络环回时延为RTT,那么在网络状况良好没有发生拥塞的情况下,发送端每个R ...
- TCP系列33—窗口管理&流控—7、Silly Window Syndrome(SWS)
一.SWS介绍 前面我们已经通过示例看到如果接收端的应用层一直没有读取数据,那么window size就会慢慢变小最终可能变为0,此时我们假设一种场景,如果应用层读取少量数据(比如十几bytes),接 ...
- TCP系列36—窗口管理&流控—10、linux下的异常报文系列接收
在这篇文章中我们看一下server端在接收到异常数据系列时的处理,主要目的是通过wireshark示例对这些异常数据系列的处理有一个直观的认识,感兴趣的自行阅读相关代码和协议,这里不再进行详细介绍 在 ...
- TCP系列35—窗口管理&流控—9、紧急机制
一.概述 我们在最开始介绍TCP头结构的时候,里面有个URG的标志位,还有一个Urgent Pointer的16bits字段.当URG标志位有效的时候,Urgent Poinert用来指示紧急数据的相 ...
- TCP系列32—窗口管理&流控—6、TCP zero windows和persist timer
一.简介 我们之前介绍过,TCP报文中的window size表示发出这个报文的一端准备多少bytes的数据,当TCP的一端一直接收数据,但是应用层没有及时读取的话,数据一直在TCP模块中缓存,最终受 ...
- TCP系列30—窗口管理&流控—4、Cork算法
一.Cork算法概述 Cork算法与Nagle算法类似,也有人把Cork算法称呼为super-Nagle.Nagle算法提出的背景是网络因为大量小包小包而导致利用率低下产生网络拥塞,网络发生拥塞的时候 ...
- TCP系列29—窗口管理&流控—3、Nagle算法
一.Nagle算法概述 之前我们介绍过,有一些交互式应用会传递大量的小包(称呼为tinygrams),这些小包的负载可能只有几个bytes,但是TCP和IP的基本头就有40bytes,如果大量传递这种 ...
- TCP系列28—窗口管理&流控—2、延迟ACK(Delayed Acknowledgments)
一.简介 之前的内容中我们多次提到延迟ACK(Delayed Ack),延迟ACK是在RFC1122协议中定义的,协议指出,一个TCP实现应该实现延迟ACK,但是ACK不能被过度延迟,协议给出延迟AC ...
随机推荐
- Redis总导航目录
NoSQL入门和概述 NoSQL入门概述 3V + 3高 当下的NoSQL经典应用 NoSQL数据模型简介 NoSQL数据库的四大分类 在分布式数据库中CAP原理CAP+BASE Redis入门介绍 ...
- MongoDB如何释放空闲空间?
当我们从MongoDB中删除文档或集合时,MongoDB并不会将已经占用了的磁盘空间释放,它会一直维护已经占用了磁盘空间的数据文件,尽管数据文件中可能存在大大小小的空记录列表(empty record ...
- 可以提高php编程效率的20个要点
整理了可以提高php编程效率的20个要点,发博客记录一下,需要的朋友可以参考. 1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍. 2.$row['id' ...
- 15-oauth2+oidc实现Server部分
1-我们使用之前项目的mvcCookieAuthSampe2进行改造 1.1 增加IdentityServer4 2-增加Config.cs文件,对IdentityServer提供相关的配置数据 u ...
- Java——多线程---18.11.22
多线程代码:Runnable方法 package com.hebust.java.third; import java.util.Random; public class SaleTicket imp ...
- 20154327 Exp6 信息搜集与漏洞扫描
基础问题回答 (1)哪些组织负责DNS,IP的管理. 全球根服务器均由美国政府授权的ICANN统一管理,负责全球的域名根服务器.DNS和IP地址管理. 全球根域名服务器:绝大多数在欧洲和北美(全球13 ...
- 实现动态的XML文件读写操作(依然带干货)
前言 最近由于项目需求,需要读写操作XML文件,并且存储的XML文件格式会随着导入的数据不同而随时改变(当然导入的数据还是有一定约束的),这样我们要预先定义好XML文件的格式就不太现实了,如何实现不管 ...
- 天津Uber优步司机奖励政策(12月28日到12月29日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- Nodejs中的流
Nodejs中的很多地方都用到了流,流是一个很常见的概念,一个http请求,控制台输入输出的形式都是流.流可以分为三种: 可读流 可写流 既能读又能写 其中第三种流又可以分为全双工流Duplex和转换 ...
- Java:当前线程运行完毕,再运行后续逻辑
一.问题描述 在程序设计中,可能存在这样的情景:主线程中存在一个子线程,子线程需要在执行完毕后为后续代码逻辑提供参数.但在代码执行时,子进程还没执行完毕,后续的代码已经开始执行了,这时候就会出现参数为 ...