2017ArchSummit-WEB加速,协议先行

这个分享主要对提升WEB性能,在协议层面讨论优化的方案,主要分三个层面优化,TCP层面,TLS层,HTTP层。文中截图来自分享ppt http://ppt.geekbang.org/slide/show/946


TCP层面的优化

使用TFO(tcp fast open),使用TFO需要linux 内核版本在3.7以上。
内核选项设置

# 打开客户端TFO
sysctl -w net.ipv4.tcp_fastopen=1
# 打开服务端TFO
sysctl -w net.ipv4.tcp_fastopen=2
# 同时打开客户端和服务端TFO选项
sysctl -w net.ipv4.tcp_fastopen=3

TFO的基本步骤如下:

  1. 客户端发送一个SYN包到服务器,这个包中携带了Fast Open Cookie请求的TCP选项;
  2. 服务器生成一个cookie,这个cookie是通过使用密钥加密客户端的IP地址生成的。服务器给客户端发送SYN|ACK响应,在响应包的选项中包含了这个cookie;
  3. 客户端存储这个cookie以便将来再次与这个服务器的IP建立TFO连接时使用;
  4. 再次发起tcp连接请求,客户端发送一个携带应用数据和以TCP选项方式存储的Fast Open cookie的SYN包;
  5. 服务器验证这个cookie,如果合法,服务器发送一个SYN|ACK确认SYN和数据,然后数据被传递到应用进程;如果不合法,服务器丢弃数据,发送一个SYN|ACK只确认SYN,接下来走三次握手的普通流程;


    2017ArchSummit-WEB加速,协议先行_第1张图片
    tfo01.png

客户端测试代码

int sockfd, n;  
char recvbuffer[1024], sendbuffer[1024];  
struct sockaddr_in servaddr;  
char buf[20] = {"hello server"};  
int ret = 0;  
  
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  
    printf ("create socket error: %s(errno: %d)\n", strerror (errno),  
            errno);  
    exit (0);  
}  
  
memset (&servaddr, 0, sizeof (servaddr));  
servaddr.sin_family = AF_INET;  
servaddr.sin_port = htons (5999);  
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  
  
ret = sendto(sockfd, buf, strlen(buf), MSG_FASTOPEN,  
        (struct sockaddr *)&servaddr, sizeof(servaddr));  
if (ret < 0) {  
    printf ("send msg error: %s(errno: %d)\n", strerror (errno), errno);  
}  
  
close (sockfd);  

在代码不需要使用connect,直接sendto发送数据。第一次交互时只是向服务器申请一个TFO cookie,数据并不在连接建立过程中送达;客户端拿到TFO cookie后,客户端每次用同样方式发送数据时都会在SYN包中携带数据。
在VM中双核2g内存的CentOS中对比普通建连和TFO建连1024次耗时

普通建连 TFO建连
457ms 285ms

服务端关键代码

// 将listenfd设置TCP_FASTOPEN选项
ret = setsockopt(listenfd, 6, TCP_FASTOPEN, &qlen, sizeof(qlen));

TFO在收到SYN的时候就创建socket并将数据提交给应用进程,在握手中传递数据。比普通模式节省了SYN|ACK与ACK的交互时间,减小了通信延迟。

TLS层面的优化

fasle start
False Start 有抢跑的意思。TLS False Start 是指客户端在发送 Change Cipher Spec Finished 同时发送应用数据(如 HTTP 请求),服务端在 TLS 握手完成时直接返回应用数据(如 HTTP 响应)。这样,应用数据的发送实际上并未等到握手全部完成,故谓之抢跑。

2017ArchSummit-WEB加速,协议先行_第2张图片
false start.png

启用 False Start 之后,TLS 阶段只需要一次 RTT 就可以开始传输应用数据。使用false start有个前提是,必须使用支持前向安全性(Forward Secrecy)的加密算法,例如ECDHE。False Start 在尚未完成握手时就发送了应用数据,Forward Secrecy 可以提高安全性
** Session Resumption**
通过会话复用,提高tls连接速度,是 TLS 握手中生成的 Session ID。服务端可以将 Session ID 协商后的信息存起来,浏览器也可以保存 Session ID,并在后续的 ClientHello 握手中带上它,如果服务端能找到与之匹配的信息,就可以完成一次快速握手。

2017ArchSummit-WEB加速,协议先行_第3张图片
tls_sessionid.png

Session Ticket
Session Identifier 机制有一些弊端

  1. 负载均衡中,多机之间往往没有同步 Session 信息,如果客户端两次请求没有落在同一台机器上就无法找到匹配的信息
  2. 服务端存储 Session ID 对应的信息不好控制失效时间,太短起不到作用,太长又占用服务端大量资源。

Session Ticket可以解决这些问题,Session Ticket 是用只有服务端知道的安全密钥加密过的会话信息,最终保存在浏览器端。浏览器如果在 ClientHello 时带上了 Session Ticket,只要服务器能成功解密就可以完成握手。

2017ArchSummit-WEB加速,协议先行_第4张图片
tls_ticket.png

** OCSP Stapling**
证书颁发者有时候需要作废某些证书,证书使用者可以通过 OCSP(Online Certificate Status Protocol,在线证书状态协议)查询证书是否已经作废。客户端会在 TLS 握手阶段进一步协商时,实时查询 OCSP 接口,并在获得结果前阻塞后续流程,这对性能影响很大。使用OCSP Stapling,可以使服务端在证书链中包含颁发机构对证书的 OCSP 查询结果,从而让浏览器跳过自己去验证的过程。服务端有更快的网络,获取 OCSP 响应更容易,也可以将 OCSP 响应缓存起来。从而提高TLS握手的速度。

2017ArchSummit-WEB加速,协议先行_第5张图片
tls_ocsp stapling.png

0-RTT Handshake
在即将发布的TLS1.3中,服务器可以把自己的 ECDH 公钥长期缓存在客户端,那么客户端就可以用缓存里的ECDHE公钥,构造一个电子信封,在第一个RTT里,直接就发送应用层数据了。

2017ArchSummit-WEB加速,协议先行_第6张图片
0RTT.png

HTTP层面

使用http2
HTTP/2 并没有改动 HTTP/1 的语义部分,例如请求方法、响应状态码、URI 以及头部字段等核心概念依旧存在。HTTP/2 最大的变化是重新定义了格式化和传输数据的方式,这是通过在高层 HTTP API 和低层 TCP 连接之间引入二进制分帧层来实现的。这样带来的好处是原来的 WEB 应用完全不用修改,就能享受到协议升级带来的收益。
HTTP/2相对于HTTP1的优点:

  1. 使用一个连接,握手少,头部做压缩,更好地利用TCP特性;
  2. 连接复用,减少域名解析的时间;
  3. HTTP/2 的多路复用特性,使得可以在一个连接上同时打开多个流,双向传输数据;
  4. Server Push,意味着服务端可以在发送页面 HTML 时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。

写在最后

针对这个分享之后,自己的一点思考。发现这些优化策略中有不少共同点,如复用,提前传输数据。在我司的产品中,在tls协议的使用中,可以尝试上述的一些优化策略,对TCP重连场景,也可以尝试使用TFO机制,但TFO需要较高的内核版本,在端上未必能支持。

你可能感兴趣的:(2017ArchSummit-WEB加速,协议先行)