浅谈TCP/IP优化方法详解

很多人常常对TCP优化有一种雾里看花的感觉,实际上只要理解了TCP的运行方式就能掀开它的神秘面纱。Ilya Grigorik 在「High Performance Browser Networking」中做了很多细致的描述,让人读起来醍醐灌顶,我大概总结了一下,以期更加通俗易懂。

 

流量控制

传输数据的时候,如果发送方传输的数据量超过了接收方的处理能力,那么接收方会出现丢包。为了避免出现此类问题,流量控制要求数据传输双方在每次交互时声明各自的接收窗口「rwnd」大小,用来表示自己最大能保存多少数据,这主要是针对接收方而言的,通俗点儿说就是让发送方知道接收方能吃几碗饭,如果窗口衰减到零,那么就说明吃饱了,必须消化消化,如果硬撑的话说不定会大小便失禁,那就是丢包了。


Flow Control

接收方和发送方的称呼是相对的,如果站在用户的角度看:当浏览网页时,数据以下行为主,此时客户端是接收方,服务端是发送方;当上传文件时,数据以上行为主,此时客户端是发送方,服务端是接收方。

慢启动

虽然流量控制可以避免发送方过载接收方,但是却无法避免过载网络,这是因为接收窗口「rwnd」只反映了服务器个体的情况,却无法反映网络整体的情况。

为了避免过载网络的问题,慢启动引入了拥塞窗口「cwnd」的概念,用来表示发送方在得到接收方确认前,最大允许传输的未经确认的数据。「cwnd」同「rwnd」相比不同的是:它只是发送方的一个内部参数,无需通知给接收方,其初始值往往比较小,然后随着数据包被接收方确认,窗口成倍扩大,有点类似于拳击比赛,开始时不了解敌情,往往是次拳试探,慢慢心里有底了,开始逐渐加大重拳进攻的力度。


Slow Start

在慢启动的过程中,随着「cwnd」的增加,可能会出现网络过载,其外在表现就是丢包,一旦出现此类问题,「cwnd」的大小会迅速衰减,以便网络能够缓过来。


Congestion Avoidance

说明:网络中实际传输的未经确认的数据大小取决于「rwnd」和「cwnd」中的小值。

拥塞避免

从慢启动的介绍中,我们能看到,发送方通过对「cwnd」大小的控制,能够避免网络过载,在此过程中,丢包与其说是一个网络问题,倒不如说是一种反馈机制,通过它我们可以感知到发生了网络拥塞,进而调整数据传输策略,实际上,这里还有一个慢启动阈值「ssthresh」的概念,如果「cwnd」小于「ssthresh」,那么表示在慢启动阶段;如果「cwnd」大于「ssthresh」,那么表示在拥塞避免阶段,此时「cwnd」不再像慢启动阶段那样呈指数级整整,而是趋向于线性增长,以期避免网络拥塞,此阶段有多种算法实现,通常保持缺省即可,这里就不一一说明了,有兴趣的读者可以自行查阅。

如何调整「rwnd」到一个合理值

有很多人都遇到过网络传输速度过慢的问题,比如说明明是百兆网络,其最大传输数据的理论值怎么着也得有个十兆,但是实际情况却相距甚远,可能只有一兆。此类问题如果剔除奸商因素,多半是由于接收窗口「rwnd」设置不合理造成的。

实际上接收窗口「rwnd」的合理值取决于BDP的大小,也就是带宽和延迟的乘积。假设带宽是 100Mbps,延迟是 100ms,那么计算过程如下:

BDP = 100Mbps * 100ms = (100 / 8) * (100 / 1000) = 1.25MB

此问题下如果想最大限度提升吞度量,接收窗口「rwnd」的大小不应小于 1.25MB。说点引申的内容:TCP使用16位来记录窗口大小,也就是说最大值是64KB,如果超过它,就需要使用tcp_window_scaling机制。参考:TCP Windows and Window Scaling。

Linux中通过配置内核参数里接收缓冲的大小,进而可以控制接收窗口的大小:

shell> sysctl -a | grep mem
net.ipv4.tcp_rmem = <MIN> <DEFAULT> <MAX>

如果我们出于传输性能的考虑,设置了一个足够大的缓冲,那么当大量请求同时到达时,内存会不会爆掉?通常不会,因为Linux本身有一个缓冲大小自动调优的机制,窗口的实际大小会自动在最小值和最大值之间浮动,以期找到性能和资源的平衡点。

通过如下方式可以确认缓冲大小自动调优机制的状态(0:关闭、1:开启):

shell> sysctl -a | grep tcp_moderate_rcvbuf

如果缓冲大小自动调优机制是关闭状态,那么就把缓冲的缺省值设置为BDP;如果缓冲大小自动调优机制是开启状态,那么就把缓冲的最大值设置为BDP。

实际上这里还有一个细节问题是:缓冲里除了保存着传输的数据本身,还要预留一部分空间用来保存TCP连接本身相关的信息,换句话说,并不是所有空间都会被用来保存数据,相应额外开销的具体计算方法如下:

 代码如下 复制代码

Buffer / 2^tcp_adv_win_scale

依照Linux内核版本的不同,net.ipv4.tcp_adv_win_scale 的值可能是 1 或者 2,如果为 1 的话,则表示二分之一的缓冲被用来做额外开销,如果为 2 的话,则表示四分之一的缓冲被用来做额外开销。按照这个逻辑,缓冲最终的合理值的具体计算方法如下:

 代码如下 复制代码

BDP / (1 – 1 / 2^tcp_adv_win_scale)

此外,提醒一下延迟的测试方法,BDP中的延迟指的就是RTT,通常使用ping命令很容易就能得到它,但是如果 ICMP 被屏蔽,ping也就没用了,此时可以试试 synack。

如何调整「cwnd」到一个合理值

一般来说「cwnd」的初始值取决于MSS的大小,计算方法如下:

 代码如下 复制代码

min(4 * MSS, max(2 * MSS, 4380))

以太网标准的MSS大小通常是1460,所以「cwnd」的初始值是3MSS。

当我们浏览视频或者下载软件的时候,「cwnd」初始值的影响并不明显,这是因为传输的数据量比较大,时间比较长,相比之下,即便慢启动阶段「cwnd」初始值比较小,也会在相对很短的时间内加速到满窗口,基本上可以忽略不计。

不过当我们浏览网页的时候,情况就不一样了,这是因为传输的数据量比较小,时间比较短,相比之下,如果慢启动阶段「cwnd」初始值比较小,那么很可能还没来得及加速到满窗口,通讯就结束了。这就好比博尔特参加百米比赛,如果起跑慢的话,即便他的加速很快,也可能拿不到好成绩,因为还没等他完全跑起来,终点线已经到了。

举例:假设网页20KB,MSS大小1460B,如此说来整个网页就是15MSS。

先让我们看一下「cwnd」初始值比较小(等于4MSS)的时候会发生什么:


Small Window

再看一下「cwnd」初始值比较大(大于15MSS)的时候又会如何:


Big Window

明显可见,除去TCP握手和服务端处理,原本需要三次RTT才能完成的数据传输,当我们加大「cwnd」初始值之后,仅用了一次RTT就完成了,效率提升非常大。

推荐:大拿 mnot 写了一个名叫 htracr 的工具,可以用来测试相关的影响。

既然加大「cwnd」初始值这么好,那么到底应该设置多大为好呢?Google在这方面做了大量的研究,权衡了效率和稳定性之后,最终给出的建议是10MSS。如果你的Linux版本不太旧的话,那么可以通过如下方法来调整「cwnd」初始值:

shell> ip route | while read p; do
           ip route change $p initcwnd 10;
       done

需要提醒的是片面的提升发送端「cwnd」的大小并不一定有效,这是因为前面我们说过网络中实际传输的未经确认的数据大小取决于「rwnd」和「cwnd」中的小值,所以一旦接收方的「rwnd」比较小的话,会阻碍「cwnd」的发挥。

推荐:相关详细的描述信息请参考:Tuning initcwnd for optimum performance。

有时候我们可能想检查一下目标服务器的「cwnd」初始值设置,此时可以数包:


Test Initcwnd

通过握手阶段确认RTT为168,开始传输后得到第一个数据包的时间是409,加上RTT后就是577,从409到577之间有两个数据包,所以「cwnd」初始值是2MSS。

需要额外说明的是,单纯数包可能并不准确,因为网卡可能会对包做点手脚,具体说明信息请参考:Segmentation and Checksum Offloading: Turning Off with ethtool。

 

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索网络
, 数据
代码
tcp ip详解 卷一、tcp ip详解、tcp ip协议详解、tcp ip详解 pdf、tcp ip详解 卷二,以便于您获取更多的相关知识。

时间: 2024-12-26 17:38:40

浅谈TCP/IP优化方法详解的相关文章

CentOS下内核TCP参数优化配置详解

那是不是所有执行主动关闭的SOCKET都会进入TIME_WAIT状态呢?有没有什么情况使主动关闭的SOCKET直接进入CLOSED状态呢?答案是主动关闭的一方在发送最后一个ACK后就会进入TIME_WAIT状态,并停留2MSL(Max Segment LifeTime)时间,这个是TCP/IP必不可少的,也就是"解决"不了的. TCP/IP的设计者如此设计,主要原因有两个: 防止上一次连接中的包迷路后重新出现,影响新的连接(经过2MSL时间后,上一次连接中所有重复的包都会消失). 为了

浅谈链轮SEO优化方法的优缺点

如果我们经常看排在百度首页的网站,发现有不少一部分是垃圾网站,按道理说垃圾网站是很难获得这么好的权重的,有的人就开始风传这些垃圾站的站点时百度员工的,借着百度工作之机给自己的站大开绿灯,可是这些揣测只是一厢情愿的事情!其实只要我们分析他们的外链结构就不难发现这些网站往往采用了一种被称作链轮的优化方式!从而让自己网站获得不错的排名! 传统的SEO策略就是通过很多有权重的外链对自己的网站进行投票,外链的权重越高,传递到自己网站上的权重就会越高,所以高质量的外链往往会帮助提高自己网站的权重,但是这些外

在Linux终端中查看公有IP的方法详解

  首先回顾一下一般的查看IP的命令: ifconfig Linux查看IP地址的命令--ifconfig ifconfig命令用于查看和更改网络接口的地址和参数 $ifconfig -a lo0: flags=849 mtu 8232 inet 127.0.0.1 netmask ff000000 hme0: flags=863 mtu 1500 inet 211.101.149.11 netmask ffffff00 broadcast 211.101.149.255 ether 8:0:2

Centos添加多个IP地址方法详解

操作如下,登陆SSH:  代码如下 复制代码 vi /etc/sysconfig/network-scripts/ifcfg-eth0:0 第二个IP,就是  代码如下 复制代码 vi /etc/sysconfig/network-scripts/ifcfg-eth0:1 第三个IP,就是 ifcfg-eth0:2(由此类推)  代码如下 复制代码 DEVICE=eth0:0 网卡设备名称 onboot=YES    随机启动 BOOTPROTO=static  静态分配IP IPADDR=*.

Android ListView适配器(Adapter)优化方法详解

Android ListView的优化,在做Android项目的时候,在用到ListView 界面及数据显示,这个时候如果资源过大,对项目来说,用户体验肯定是不好的,这里就对如何优化做了详细介绍: Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View.想过没有? 在我们的列表有1000000项时会是什么样的?是不是会占用极大的系统资源? ListView的Adapter的作用如下图所示: 先看看下面

从HTML布局浅谈网站的优化方法

SEO是一门学问,涉及到的东西也很广泛,很多朋友在做SEO的时候往往会关注一些外部的东西,比如外部链接,或者发广告等等,而忽视了自己网站内在的一些东西,今天我就和大家聊聊关于HTML布局中的一些东西,希望对大家有所帮助,也欢迎大家共同探讨. 一.编写良好的HTML结构 一个良好的HTML文档结构无论是对搜索引擎,还是对代码人员(切片人员或者程序员)都是有百利而无一害的.回想一下人们之所以抛弃TABLE(表格)布局,就是因为使用TABLE布局产生了大量的冗余代码,而且为了到达一定的视觉效果,只能套

浅谈ASP.NET Core 中间件详解及项目实战_实用技巧

前言 本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World. 中间件(Middleware)的作用 我们知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终到达我们写的代码中.那么中间件就是在应用程序管道中的一个组件,用来拦截请求过程进行一些其他处理和响应.中间件可以有很多个,每一个中间件都可以对管道中的请求进行拦截,它可以决定是否将请求转移给下一个中间件. asp.net

VMware下CentOS6.4网卡设置为桥接模式静态IP配置方法详解

1.禁用网络管理器 # chkconfig NetworkManager off # service NetworkManager stop 2.创建用以桥接的虚拟网卡 # cd /etc/sysconfig/network-scripts # cp ifcfg-eth0 ifcfg-br0 注:修改之前做好备份啊,万一有问题还可以还原! 3.编辑ifcfg-br0 # vi ifcfg-br0 DEVICE="br0" TYPE="Bridge" ONBOOT=&

CentOS Cpu性能优化方法详解

调节CPU对应某个程序的使用: 一.使用taskset充分利用多核cpu,让cpu的使用率均衡到每个cpu上 #taskset -p,    设定一个已存在的pid,而不是重新开启一个新任务 -c,    指定一个处理,可以指定多个,以逗号分隔,也可指定范围,如:2,4,5,6-8. 1,切换某个进程到指定的cpu上 taskset -cp 3 13290 2,让某程序运行在指定的cpu上 taskset -c 1,2,4-7 tar jcf test.tar.gz test 需要注意的是,ta