TCP Fast Open知识

TCP Fast Open定义

TCP Fast Open(TFO)是用来加速连续TCP连接的数据交互的TCP协议扩展,原理如下:在TCP三次握手的过程中,当用户首次访问Server时,发送SYN包,Server根据用户IP生成Cookie(已加密),并与SYN-ACK一同发回Client;当Client随后重连时,在SYN包携带TCP Cookie;如果Server校验合法,则在用户回复ACK前就可以直接发送数据;否则按照正常三次握手进行。

起源

由Google于2011年的论文(http://conferences.sigcomm.org/co-next/2011/papers/1569470463.pdf)中提出,IPV4的TFO已经合入Linux Kernel Mainline,Client内核版本为3.6;Server内核版本为3.7。

Google研究发现TCP三次握手是页面延迟时间的重要组成部分,所以他们提出了TFO:在TCP握手期间交换数据,这样可以减少一次RTT。根据测试数据,TFO可以减少15%的HTTP传输延迟,全页面的下载时间平均节省10%,最高可达40%。

目前互联网上页面平均大小为300KB,单个object平均大小及中值大小分别为7.3KB及2.4KB。所以在这种情况下,多一次RTT无疑会造成很大延迟。

2011年6月,对Google webServer进行连续7天数十亿次针对80端口的请求分析,包括搜索、Gmail、图片等多个服务。其中cold requests为:新连接上的请求;warm requests为已有连接上的请求;All requests为所有连接上的请求(cold requests + warm requests)。cold requests及all requests中TCP握手时间在整个延迟时间中的占比如图 1 所示

图 1 Cold Req及All Req的三次握手在整个连接生命周期的时间百分比

分析结果显示,在cold requests中,TCP握手时间占延迟时间的8%-28%;即使统计所有的请求,TCP握手时间也占到了延迟时间的5%-7%。

谷歌对谷歌浏览器的进行了28天的连续数据分析(通过了用户授权):数据不仅仅是针对谷歌服务,也涉及到所有网站的请求。通过对上十亿条记录的分析,发现即使使用了Http1.1的keep-alive功能,依然有33%的请求是在新连接上发起的。可能原因:为了加快下载速度,新建数10个连接;主机和NAT也会主动断开闲置的keep-alive连接;为了省电,手机浏览器关闭闲置的连接。

为了理解TCP的三次握手对整个连接交互的影响,将分析数据进行绘图,如图 2所示

图 2 Http请求延时的累积分布函数图(CDF)

其中,X轴为网络交互延时(单位为s), Y轴为以百分比表示的HTTP请求的累积分布;All Req为三次握手在所有请求中的时间占比; Cold Req为新连接上的三次握手的时间占比; Cold Req no Hsk代表去除了三次握手时间的Cold Req的时间占比。

Cold Req基本比All Req慢50%(DNS查找、慢启动、SSL握手、TCP握手导致),而TCP握手时间在Cold Req延迟时间中往往占比了25%。

因此,Google设计了TCP Fast Open.

详解

  • 流程

TCP Fast Open流程图如图 3所示

图 3 TCP Fast Open 流程图

如图 3所示,TFO的的流程如下:

  1. 用户向Server发送SYN包并请求TFO Cookie;
  2. Server根据用户的IP加密生成Cookie,随SYN-ACK发给用户
  3. 用户储存TFO Cookie

当连接断掉,重连后的流程如下:

  1. 用户向Server发送SYN包(携带TCP Cookie),同时附带请求;
  2. Server校验Cookie(解密Cookie以及比对IP地址或者重新加密IP地址以和接收到的Cookie进行对比)。

        如果验证成功,向用户发送SYN+ACK,在用户回复ACK之前,便可以向用户传输数据;

        如果验证失败,则丢弃此TFO请求携带的数据,回复SYN-ACK确认SYN Seq,完成正常的三次握手。

        如果Cookie在网络传输的过程中被丢弃,Client在RTO后,发起普通的TCP连接,流程如图 4所示

图 4 Cookie被网络丢弃

3. 如果在SYN包中的数据被接受,那么Server可以在收到Client的ACK之前回复该请求的响应报文

4. ClientACKServer的SYN。如果Client的数据没有得到Server的ACK,那么Client会通过ACK重传该请求。

5. 随后的操作和普通的TCP连接一致

建立了TFO连接而又没有完成TCP连接的请求在Server端被称为pending TFO connection,当pending的连接超过上限值,Server会关闭TFO,后续的请求会按正常的三次握手处理。

如果一个带有TFO的SYN请求如果在一段时间内没有收到回应,用户会重新发送一个标准的SYN请求,不带任何其他数据。

Cookie是用来验证Client的IP所有权的加密字符串。Server负责产生及验证Cookie。Client缓存Cookie以及在随后的连接初始化阶段将Cookie返回给Server。

Server通过加密Client的源IP产生16字节长度的Cookie(通过AES-128算法)。加密和解密Cookie很快,可以和正常的SYN及SYN-ACK包的处理时间差不多。

为了确保安全及用户IP会变(如DHCP),Cookie值会隔一段时间变化一次。

Cookie结构如图 5 所示

图5 Cookie结构

         如图 5所示,如果没有Cookie或者Cookie值为空,则表明是Client向Server请求Cookie;如果Cookie有值,表明是Server向Client发送Cookie或者Client通过TFO执行Fast Opem.

  • TFO与Wireshark

通过Wireshark抓包可以看TFO流程,如图6所示:

图6 Wireshark抓包与TFO

Fast Open Cookie选项在TCP Options中,从No.7包中可以看到,Fast Open Cookie的Kind为34, 长度为10,Cookie为0x1a39d8e2100b247e。

  1. 首先Client发起TCP连接(端口为57520),在SYN包中带有一个FOC选项,向Server请求Cookie(No.1号报文)
  2. Server端回复SYN-ACK包,其中携带一个FOC选项,Cookie域为0x1a39d8e2100b247e(No.7号报文)
  3. Client发送一个"hello"消息后关闭连接(No.5号报文),Server端也断开连接(No.6号报文)
  4. Client通过57522端口向Server发起TFO的SYN,携带Cookie及数据(No.7号报文)
  5. Server回复SYN-ACK(No.9号报文)
  6. Client回复ACK(No.10报文)

 

  • 开启TFO

在Linux支持TFO的内核版本下(Client内核版本为3.6;Server内核版本为3.7),在sysctl.config(vim /etc/sysctl.conf)中添加:

net.ipv4.tcp_fastopen = 3

其中1表示客户端开启,2表示服务端开启,3表示客户端和服务器同时开启

  • 示例代码

Server主要代码:

 
  1. sfd = socket(AF_INET, SOCK_STREAM, 0);   // Create socket

  2.  
  3. bind(sfd, ...);                          // Bind to well known address   

  4.  
  5. int qlen = 5;                            // Value to be chosen by application

  6.  
  7. setsockopt(sfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));   

  8.  
  9. listen(sfd, ...);                        // Mark socket to receive connections

  10.  
  11. cfd = accept(sfd, NULL, 0);              // Accept connection on new socket

  12.  
  13. // read and write data on connected socket cfd

  14.  
  15. close(cfd);

注意:Server需要设置TCP_FASTOPEN属性

Client主要代码

 
  1. sfd = socket(AF_INET, SOCK_STREAM, 0);   

  2.  
  3. sendto(sfd, data, data_len, MSG_FASTOPEN, (struct sockaddr *) &server_addr, addr_len);

  4.  
  5. // Replaces connect() + send()/write()   

  6.  
  7. // read and write further data on connected socket sfd

  8.  
  9. close(sfd);

注意:Client不能用connect,只能用sendto及sendmsg

TFO性能

 为了验证TFO的性能,Google做了一些实验。        

  • 页面加载时间

Google对amazon.com、nytimes.com、wsj.com、TCP Wikipedia page等网站进行了使用TPO及不使用TPO进行了测试,设置一系列的RTT时间:20ms、100ms、200ms,记录页面的加载时间,每个页面采集120个数据。

测试结果如图 7 所示,(PLT 为Page load time)

图 7 页面加载时间

如图 7所示,RTT时间越大,TFO的效果越明显。当RTT为200ms时,改善达到了11%-41%。

  • Server CPU

由于Server产生Cookie时需要加密,验证Cookie时需要解密,Google也测试了TFP开启时,Server的CPU使用率,如图 8所示

图 8 CPU使用率

如图8所示,当开启TFO时,CPU的使用率并不高,在某些区间甚至低于普通的TCP。

安全性

在TFO下,依然存在一些问题,如伪造TFO SYN攻击(通过DHCP及NAT、Moles获取有效的Cookies),这种场景下,Server资源会被攻击耗尽。

图 9显示了TFO的SYN-flood攻击和普通的TCP SYN-flood攻击对比情况

图 9 SYN-Flood攻击对比

结论

  1. TFO在TCP的第一次握手时就携带请求报文,对于35%的http请求,可节省一个RTT
  2. Cookie是加密的,一定程度上减少了攻击可能性

参考资料

  1. https://tools.ietf.org/html/rfc7413
  2. http://blog.sina.com.cn/s/blog_583f42f101011veh.html
  3. http://conferences.sigcomm.org/co-next/2011/papers/156947046pdf
  4. https://en.wikipedia.org/wiki/TCP_Fast_Open#cite_note-2
  5. https://www.ietf.org/proceedings/80/slides/tcpm-3.pdf
  6. https://datatracker.ietf.org/doc/rfc7413/?include_text=1
  7. https://tools.ietf.org/html/rfc7413
  8. https://lwn.net/Articles/508865/

猜你喜欢

转载自blog.csdn.net/liujiayu2/article/details/111702568