趣谈TCP协议的缺陷

100人眼里有100种哈姆雷特,谈谈我眼中的TCP。

TCP做为一种可靠传输协议,其核心目标是把应用层的数据正确、可靠、高效传输到对端,而TCP所依赖的IP网络是一个原始的丛林世界,丢包、乱序、延迟不固定。

TCP有一个孪生兄弟叫UDP,UDP是一大老粗,但非常听话。UDP在IP网络丛林里,严格执行自己的主人(应用层)的旨意,主人让发1000个/秒UDP包,UDP就一定会发那么多,也许这1000个包最终到达目的地的只有200个,其它的800个消失在丛林世界里无影无踪。


TCP是举止优雅的绅士,对丛林世界的潜规则很反感,但又有极强的适应能力,能够从容应对一切的挑战。TCP也接到老板的吩咐:把1000个数据包1秒之内发到目的地!

TCP委婉地表达自己的想法,可以准确无误地发到目的地,但时间无法保证!

TCP凡事喜欢预约,每当需要拜访对方时,总会提前打过招呼(建立连接),只有对方在、并且接受预约(连接建立),才会带着老板的数据包去拜访对方。

TCP是这么做的:
先发一个包,等一个包的确认收到,可以得到一个往返时间RTT
发两个,收到确认,得到第二个RTT,与第一个相加算平均SRTT

一直两倍的指数增长,一直计算SRTT。

直到检测到丢包,或retransmission timer 超时、或收到至少三次duplicated ACK。

1.TCP决定在SRTT时间内发送个数指数减半

2.如果收到ACK,则持续计算SRTT,发送个数线性增长,一个SRTT多发一个包。

3.如果依然没有收到ACK,重复步骤1、2

这是TCP的自适应流量控制算法,决定TCP能发多快,由这个公式得到:

Delivery Rate =CWND/SRTT,其中

CWND = 可发送包的个数 * 包的大小

SRTT 是平滑RTT,动态测量的结果

如果SRTT不变,CWND越大,发送速率越快。

如果CWND不变,SRTT越小,发送速率越快。

但一旦网络拥堵,路由器缓存队列使得SRTT变大,所以rate 会变小。

如果缓冲队列尾丢(溢出),意味着有丢包,发送方肯定能检测出,指数减小CWND,这样rate 也会突减1/2。

TCP就是通过这种小速率探测网络拥堵、指数增加发送速度、检测到丢包、发送速率减半、直到不再检测到丢包、线性增长发送速率、检测到丢包、再指数减小发送速率…

TCP流控算法的关键,是基于丢包,有否丢包是唯一的判断依据,是加油门还是踩刹车。

但TCP由于对网络了解的很片面,无法分辨丢包是什么原因造成的

1. 网络真的拥堵而丢包

2. 线路质量差CRC校验失败丢、或信号干扰丢

3. IP包乱序而引起的误判


只有情况1是需要踩刹车的,而情况2、3并不需要。

Google BBR算法则提出基于带宽实时测量的算法,对于每个有数据的TCP包都测量其RTT,动态计算SRTT,这个比传统TCP计算的SRTT更精准,因为传统的TCP是一个SRTT时间周期内测量一次,而不是每个有数据的TCP包都测量。

根据实时带宽值的趋势,是增还是减,如果增,说明带宽还有空间,可以乐观,在当前的delivery rate 的基础上 * 大于1的系数,等于加小油门,发送速率攀升。

如果是减,则需要谨慎,在当前的delivery rate 的基础上 * 小于1的系数,等于小踩刹车,发送速率放缓。

BBR算法不依赖于丢包,可以克服传统TCP对丢包的过分敏感与过激反应,避免发送速率骤增与骤减,使得整体发送速率在一个小范围内波动,更平缓、更平滑。

这是对传统TCP流控算法的一个优化。

至于TCP其他的需要改进的,已经通过TCP option做了补丁,比如:

  • Scaling Window 应对长肥管道

  • Selective ACK  应对高丢包率场景。

  • Timestamp  应对序列号回滚RTT测量的精度。

  • Authentication Option  应对数据完整性挑战。

  • TCP Cookie  应对SYN Flooding DOS攻击。

  • FAST TCP Open  应对TCP传输数据延时大。