1. TFO背景
当前web和web-like应用中一般都是在三次握手后开始数据传输(第三次可以开始传输),相比于UDP,多了一个RTT的时延,即使当前很多应用使用长连接来处理这种情况,但是仍然由一定比例的短连接,这额外多出的一个RTT仍然对应用的时延有非常大的影响。TFO就是在这种背景下面提出来的。
TFO(TCP fast open)是TCP协议的experimental update,它允许服务器和客户端在连接建立握手阶段交换数据,从而使应用节省了一个RTT的时延。但是TFO会引起一些问题,因此协议要求TCP实现必须默认禁止TFO。需要在某个服务端口上启用TFO功能的时候需要应用程序显示启用。
2. TFO过程
-
在使用TFO之前,client首先需要通过一个普通的三次握手连接获取FOC(Fast Open Cookie)
client发送一个带有Fast Open选项的SYN包,同时携带一个空的cookie域来请求一个cookie
server产生一个cookie,然后通过SYN-ACK包的Fast Open选项来返回给client
client缓存这个cookie以备将来使用TFO连接的时候使用
-
执行TFO
- client发送一个带有数据的SYN包,同时在Fast Open选项中携带之前通过正常连接获取的cookie
- server验证这个cookie。如果这个cookie是有效的,server会返回SYN-ACK报文,然后这个server把接收到的数据传递给应用层。如果这个cookie是无效的,server会丢掉SYN包中的数据,同时返回一个SYN-ACK包来确认SYN包中的系列号
- 如果cookie有效,在连接完成之前server可以给client发送响应数据,携带的数据量受到TCP拥塞控制的限制(RFC5681,后面文章会介绍拥塞控制)。
- client发送ACK包来确认server的SYN和数据,如果client端SYN包中的数据没有被服务器确认,client会在这个ACK包中重传对应的数据
- 剩下的连接处理就类似正常的TCP连接了,client一旦获取到FOC,可以重复Fast Open直到cookie过期。
通过整个过程,我们可以看到TFO的核心是一个安全cookie,服务器使用这个cookie来给客户端鉴权。一般来说这个cookie应该能鉴权SYN包中的源IP地址,不包含端口(client每次的端口都可能不同),并且不能被第三方伪造。为了保证安全,过一段时间后,server应该expire之前的cookie,并重新生成cookie。cookie验证通过,server在发送SYN-ACK的时候,如果有待发送数据也同样可以携带数据。
client在缓存cookie的时候,协议同样建议缓存Maximum Segment Size(MSS),MSS代表了对端能接收的最大TCP段,这样client在执行TFO的时候,SYN包可以携带的数据量大小就有了一个参考。即使缓存了MSS,也建议client SYN包中数据不要超过典型的MSS,即IPV4的1460bytes和IPV6的1440bytes。如果没有缓存MSS,则SYN包中的数据大小限制在默认的MSS,IPV4为536bytes(RFC1122),IPV6为1220bytes(RFC2460)。
client在收到服务器SYN包但是没有ACK之前自己发出的数据时候,或者ICMP错误或者根本没有收到SYN-ACK响应的时候,client至少应该要在对应的连接路径上临时禁止TFO功能。
FO场景下,client在超时重传SYN包以及server超时重传SYN-ACK报文的时候应该去掉Fast Open选项和对应的数据,以免因为不兼容TFO而导致连接建立失败。
3 关闭cookie的fastopen
如果在数据中心内部,通过三层防火墙进行安全防护,可以直接关闭cookie,降低CPU消耗。那么如何关闭cookie功能呢?
从第274行可以看出,只要设置net.ipv4.tcp_fastopen值涵盖TFO_SERVER_COOKIE_NOT_REQD就可以,下面我们看一下她的值
我们只要设置tcp_fastopen的值涵盖0x200,同时还要保证最低位的2个比特位为1来开启TFO,所以就可以设置为0x203或者0x207。
下面我们看看这样设置0x207以后的TFO的表现,也就是Client端都不携带cookie。可以看到可以正常开启TFO,server端ACK了syn数据包中携带的Data数据。在SYN的包里面也没有看到cookie。
我们再来看一下设置0x203以后的表现,我们为了验证server端对cookie没有校验,我们同时修改server端的key。可以看到正常TFO连接,server端ack了syn数据包中携带的10字节数据。
4 Nginx
这里单独说明一下Nginx,从Release-1.5.8的版本开始支持TCP_FASTOPEN,配置也非常简单 listen 80 fastopen=1024
5 广域网TFO可用性
由于中间路由器、交换机等设备可能不支持,导致TFO在互联网环境下可能失败,从而弱化到标准的TCP握手,甚至导致更恶劣的重传,不过从Anna Maria Mandalari博士的测试数据来看,只有2.18%的SYN数据包会被直接丢弃,引起重传。
下面是博士团队在2015年对18个国家、22个ISP环境下进行TFO的测试数据
Successful:is able to perform a TFO connection
No option SYN: middleboxes drop packets with unknown TCP options and we receive the SYN without option
No option no SYN:middleboxes drop packets with unknown TCP options and we do not receive the SYN without option
No data SYN:middleboxes drop packets with data in the SYN packet and we receive the SYN without data
No data no SYN:middleboxes drop packets with data in the SYN packet and we do not receive the SYN without data