加快网络速度-TCP优化

如今, 时间就是金钱. 不像之前浏览一个网页就是一个奢侈品. 现在, 网速愈来愈快, 下个2GB的东西, 1分钟就行了.
那, 我如今网速很慢,应该怎么提升的个人网速呢?
提高网速的不二法门就是... 买宽带~
233333~ 固然,这只是, 给用户的建议。 对于, 咱们程序员来讲, 花钱就是最痛苦的事. 这里, 咱们须要用咱们本身的双手去提高网速.
这里,咱们主要看看,在TCP这边怎么提高网络速度.html

常见的TCP 延时事务

TCP是网络通讯很重要的一个协议,程序员的基本功也就在这, 最出名的应该算是TCP的3次握手了. 不过,这里3次握手不是我要阐述的, 有兴趣的同窗,能够看看TCP3次握手. 那还有其余能形成TCP时延的事务吗?
固然有啊. 常见可以形成的事务有如下几种.node

  • 延迟确认linux

  • nagle算法程序员

  • slow-start算法

  • 端口耗尽数据库

延迟确认

当你在进行网络数据传输, 成功发送数据包时, 服务器会给你返回一个ACK进行确认。 可是为了防止,网络的堵塞,一般,服务器在接收该数据时,会对ACK进行延时, 若是在必定时间内(一般为200ms), 有另外的数据来源时, 则会将2次ACK包一块儿发送,减小宽带.
以下图所示:

总结一句话:segmentfault

ACK every second packet, or a single packet after the Delayed ACK timer expireswindows

即,有两个包当即到来当即发送ACK, 没有的话,等一会,实在没有则将该次ACK 单独发送.缓存

nagle算法延时

这是nagle 建立的一个算法,和延迟确认同样也是用来解决网络堵塞问题. 不过,他针对的是Sender一端. 众所周知的TCP的大小有40 bytes. 若是你的数据包内容才1B的话, 这样传输的价值就很是小了.因此,聪明的nagle想了想,这样不行,得让小数据包在缓存里面待一段时间,等数据多了再一块儿发送,若是是在没有其余数据了, 超过nagle算法设置的时延后,那就只能单独发送了.安全

nagle 和 确认延迟共同做用

假设如今有这样一个场景, 有两个包, 一个已经发送,另一个因为尺寸过小, 被放在缓存当中. 此时,你的nagle算法是开启的, 那么此时,你须要等到前面一个包被确认以后才能发送.那么这样算起来,在这个特殊状况下,你偶数包的延迟时间是=== nagle+确认延迟. 虽然,这种状况很特殊,可是在高并发的状况下,任何东西都是有可能出现的.

nagle的缺陷

因为nagel主要是针对小数据包, 因此对于小包的影响很大. 好比: 你使用HTTP只是发送GET请求,要求数据库进行相关的取操做,而返回的数据很小. 那么,这时候nagle会让你欲哭无泪~

解决缺陷

针对于确认时延, 这里因为是系统本身设置的.
在windows 里,确认延迟通常为200ms.(如今谁还用windows)
而在*nx里,延时被调整到15-40ms.
不过在linux里面可使用tcp_delack_min进行修改. 不过对于15-40ms, 俺认为这个应该没有太大的影响. 不必大动干戈进行改动。 不过,对于nagle算法延时,这个问题就比较严肃了. 在nodeJS里面咱们通常使用socket.setNoDelay([noDelay])来进行设置.

slow start为什么物

slow-start 是为了解决网络延迟而被设计出来的一个算法. 用来逐步增长数据包的发送量,直到发送端和接收端可以承载的最大值为止.
在正式介绍slow-start 工做流程以前,咱们须要掌握几个基本的概念。

TCP 里面的window

window是TCP报文里面的一部分. 咱们看一下TCP协议内容.
此处输入图片的描述
就是里面的window. 他主要就是用来描述 链接可以承受的包的大小, 由于一旦你的包过大,会形成包的废弃,而致使重发。window 就是起到提升传输效率的做用.
那window 是怎么肯定的呢? 首先咱们须要明白, 每一方的 congestion window 的最大值,都只有本身知道,那要猜想到对方的最大值话,就只能一步一步的逼近. 但第一次的值应该怎么设置呢? 其实这是有标准的.
首先,咱们须要了解另一个名词--MSS][4. 他是congestion window 的基础值. MSS 一般为1460B(1500-20 for IP - 20 for TCP). 而后,congest control 定义了一套公式:

If SMSS > 2190 bytes:

IW = 2 * SMSS bytes and MUST NOT be more than 2 segments
If (SMSS > 1095 bytes) and (SMSS <= 2190 bytes):
IW = 3 * SMSS bytes and MUST NOT be more than 3 segments
If SMSS <= 1095 bytes:
IW = 4 * SMSS bytes and MUST NOT be more than 4 segments

因此由上面算下来, window = MSS * 3 = 4380B. 这就是sender's congestion window 的初始值. 这里的3还有另一个名词--initcwnd(下文会有介绍).
ok~ 基本概念有了, 那 how does slow-start work?

slow-start 是怎么工做的?

  • 在首次发送信息时, Sender 会初始化一个包, 而且该包里面包含了一个比较小的 堵塞窗口(其实就是代表窗口的容载量--bytes). 他的大小是由 MSS 决定的.好比,咱们的MSS为1460B, 那么咱们初始化的congeston window就能够为2920B. 即,至关于发送了2个小分组. (不理解,见window size)

  • 接受者接受到包以后, 会返回一个ACK包,并附上 receiver's window size(一般,会比sender发送过来的大). 若是, receiver 没有响应, 那么sender 就知道本身 的包太大了, 而后会自行改小 而后再发送.

  • sender接受到receiver 的 ACK后,此时就在上一次发送的基础上额外加上一倍的MSS. 即, 上一次,我发送了2个MSS大小的包, 那么此时,会接受到两次ACK确认,接收到以后,我就能够增大window size, 向receiver额外再发送一倍---4个MSS大小(2920 + 1460 + 1460). 如此往复,直到两边的window size 到达上限以后,那么slow start 就已经完成了.

其实,上面的传输过程,咱们可使用一个图表来表示. 这是,在下载一个文件时抓包时的图.(抓包工具你用什么均可以,不过最经常使用的是fiddle和wireShark)

x-axis 是 时间, y-axis 是 发送的序列号(用来表示每一个包是整个资源的哪一部分). 注意!!! 里面的一个点 就是一个包. 咱们能够数一数, 第一个有2个dot, 第二个有4个dot, 第三个有8个dot... 后面确定会有一个上限值, 那么,此时就已经达到最大传输速度了. ok~ slow-start要作的工做就已经完成了。 那么该次的Connection 应该算是最优connection, 因此对于已经创建好的connection实现重用也是TCP优化很重要的一部分.

slow start 好处

  • 减小链接断开次数: 由于包不会因为网络堵塞而丢失

  • 用户可以享受更快的下载速度,由于此时slow-start已经找到了最大的链接速度了

  • 下降网络堵塞状况

可是,好处就这几个,可是对于大量链接须要创建时, slow-start 对其影响 就比较呵呵了。 那应该若是优化slow-start呢?

解决slow-start时延

上面提到过,congestion control 有一个计算机制, 用来肯定初始化时的包的传输量.

If SMSS > 2190 bytes:

IW = 2 * SMSS bytes and MUST NOT be more than 2 segments
If (SMSS > 1095 bytes) and (SMSS <= 2190 bytes):
IW = 3 * SMSS bytes and MUST NOT be more than 3 segments
If SMSS <= 1095 bytes:
IW = 4 * SMSS bytes and MUST NOT be more than 4 segments

上面的数字,咱们就能够称做为initcwnd(the initial congestion window parameter). 他用来规定你的sender 在初始化时,发送数据包的数量. 因为一般规定MSS 通常为1460B, 因此,initcwnd 的数量通常规定为2.(由于,要比上限值小才行, 防止丢包)
可是,这个只是对于很老的机器来讲, 如今你们的笔记本基本上都是00后, 配置已经远远超过之前的台式了. 因此,通常而言,receiver window size 应该不会很低。 下图是操做系统和对应的window size的最大值.

就算是XP 他也能够接受 65 535B 大小的包. 若是你sender发送的仍是 2920B 的话,这就有点 太慢了. 因此,在配置服务器的时候(特别是*nx), 咱们须要对其initcwnd的值,更改一下. 减小他slow-start的时间.
在linux 下, 咱们可使用:

  • ip route show; //查看电脑设置的initcwnd初始值

  • sudo ip route change default via 192.168.1.1 dev eth0 initcwnd 10 //将initcwnd 设置为10

  • ip route show; //检查initcwnd 是否为10

在windows 2008 Server 下的更改请参靠: initcwnd

提高了initcwnd,有什么用?

那这样作到底有什么效果呢?咱们看图说话:

能够看到,随着initcwnd的提升, 下载的时间逐渐变慢. 可是,initcwnd 也不能无限制提升, 能够看到从10到20, 时间就基本上没什么变化了. 因此,通常推荐提高到10就能够了.

另外一方面,initcwnd对于CDN 的优化,也是很是重要的。 要知道CDN 原本就是以快著名. 咱们先来看看CDN 是如何工做的.

HOW CDN works

CDN凭借他特有的机制,高速通道,CDN Cache,域名分片等特性. 成为了云平台上必不可少的一个特性.
但,CDN究竟是怎么工做的呢?
CDN是云平台的产物,因此他必须依赖的就是众多的服务器. 一般来讲, CDN 有不少 Points of Presence (PoPs) 分布在全国或者说全世界各地,用来加速文件传输的.
若是,咱们的文件没有放在CDN上,那么,他的传输过程是怎样的呢?

像这里,从Russia 到 America中间通过无数的节点进行传输,可想而知,随随便便丢个包,那么, 你传输就得重头再来~ 形成的网络堵塞我就不说了,关键用户等不了~ 对于这种状况,考虑直接上CDN。 咱们来看一下,带上CDN的时候.

当你的文件放在CDN上时, 用户首次使用该文件时, 这时候最近的CDN Server 会向 Origin Server 请求文件,而后该文件就会保存在该CDN Server 以备用户下一次读取. 因此, 通常而言,第一个吃螃蟹的人,贡献是最大的.
另外,若是你请求的资源是动态生成的,那么CDN Cache你的Content也是没有什么卵用的. 因此CDN 还有另一个机制-- Super Highway. 不一样于前面的without CDN 时候的传输方式, 通过独立的ISP, 用户等到花儿都谢了资源才到, 这里, CDN 会创建一个高速通道, 将动态资源高速传递.
此处输入图片的描述
云平台内部会自建算法,计算两点位置传输的最短路径, 而后找到对应服务器进行传输. 因此,远距离传输也是CDN的一大亮点。 不过因为距离长,稳定性和安全性的要求也会增长. CDN服务器就必须保证 本身 自己可以过滤掉一些DDOS attackers 以及 可以承受部分的DDOS攻击.

ok~ CDN 基本内容算是说完了, 经过上面的介绍,为了达到'高速'这个蜜汁weapon. 提高initcwnd 也是必不可少的一部分。 国外的CDN,一般会到10+. 这是linux kernel 内置的(3.0版本以上). 能够说, 你的initcwnd 越高, 对机器的性能要求也越高。 因此,对于本身的云平台有蜜汁自信的,他的initcwnd确定会高。 这里,我放一份,国外的CDN 服务商的 initcwnd数.

能够看到. Cachefy 像是开挂似的, initcwnd数都到70了. 不过,initcwnd只是做为一个参考,服务商性能的优劣并不只仅只有initcwnd这一个参数.

端口耗尽和TIME_WAIT

还记得4次挥手的时候,发生的故事么?
在双方发送一次FIN包以后,还须要通过TIME_WAIT的2MSL时延以后,才能够正式宣告结束.(MSL是报文在网络中存活的最大时间- Maximum Segment Lifetime)具体的4次回收流程以下:

只有当TIME_WAIT正式结束以后, 端口的利用才有可能被释放. 因此,TIME_WAIT的2MSL 也可算是一个时延.
这里,咱们须要了解一下,在TCP通讯中,很重要的一个概念就是链接惟一性. 确认惟一性通常只要4个值便可.

  • client IP Address

  • client port

  • server IP Address

  • server port

这也是TCP报文和IP报文里面必不可少的部分。
因此,因为2MSL时延的关系,会形成client的端口堵塞。有可能会形成端口耗尽的结果。 那对于server 有什么影响呢?
在普通HTTP 请求当中对于server的影响能够说没有,但若是你使用的是socket通讯的话,那么影响就比较大了, 由于在断开的时候,server 的socket 就会处于TIME_WAIT状态, 有可能形成服务器的端口耗尽,在nodeJS里面可使用setTimeout()进行 自动断开等优化操做.
可是, 为何客户端必定要有2MSL的延时呢?
很简单,就是保证数据的正确性.
这里,咱们能够这么考虑, 若是没有2MSL, TCP链接的数据有可能发生神马状况?
如图:
point_1 向point_2发送信息时,有一个包,过分延时(在2MSL内). 但此时,point_2向point_1发送断开请求,没有时延的状况下, 二者会当即断开.而后接着, point_1又向point_2 创建3次握手链接。 完成以后,延迟的包又发送过来,因为包的IP和port都是正确的,point_2固然会无条件处理,而结果就是,将现存的数据给改变--有可能形成数据bug.因此,2MSL的时间颇有必要.但,因为2MSL的必要性,会对于某些大并发操做的链接产生巨大影响, 好比使用siege,ab进行基准测试, 大并发查询数据库等等. 因此, 对于此次,实现链接的reuse就很是必要了.

相关文章
相关标签/搜索