Nginx+HTTP3 初体验

http3协议近日发布了第27个草案,这也是经历了近3年半之后比较接近最终版本的草案了。而nginx官方也推出了基于quic分支来支持http3的官方版本。

为什么要推出HTTP3协议。

http/1.1的问题

当前我们在使用http协议的大部分还是停留在http/1.1,http2协议到今天为止好像刚刚到半数,http/1.1在互联网发展中逐渐暴露一些问题:

  1. 在同一个连接上只能一来一回,需要处理完一个http事务之后才能处理下一个。而浏览器通常限制同一域名建立连接的个数。例如Chrome限制同一域名只能建立6个连接。这样如果一个页面上资源很多且所有资源处于同一域名的情况下,就不能很好的利用当前的大带宽。毕竟我们现在的家庭网络都要达到百兆的带宽了,这就好比我们有一个非常宽的桥,要开过去一百辆汽车,这种情况就是我们一辆一辆排着队开过这个桥。如果注意观察有些网站域名的起名规则就可以看到是为了解决这个问题,例如static001.xxxx,static002.xxxx,这些通常都是CDN加速域名。这样做的好处一是可以分类存储,避免在回源的时候文件过多影响加载速度,另一个就是可以很好的应对浏览器对同一域名建立连接个数的限制。可以同时发起更多的连接,从而加快整个页面的加载速度。毕竟现在一个页面上的资源都有几十甚至上百了。
  2. 为了实现HTTP协议的无状态特性,每次传输都要携带大量元数据例如cookie、header。而这些数据通常都是不怎么变的,而真正要传输的包体可能很小。使得http/1.1协议的传输效率低下。
  3. http/1.1不支持服务器推送。尽管曲线救国推出了websocket协议,但是websocket也不支持多路复用,在同一个连接上还是一来一回。而且websocket协议在可伸缩性上有所欠缺。
  4. http/1.1传输中无法终止一个请求,如果一定要终止的话,就要断开连接了。

基于以上http/1.1的缺点,我们做过一些努力:例如合并多张小图为一张大图在客户端利用js切割使用。合并多个js为一个js、合并多个请求为一个请求例如tengine的http_concat_module,总之就是为了提高有效数据的占比。减少请求,加快速度。但是这些解决方案常常也带来一些麻烦例如合并多个js为一个js,如果一个js需要修改就需要重新打包,牵一发而动全身。

HTTP2协议的优势

http2协议通过stream ID在同一个连接上实现了多路复用,这样就可以在同一个连接上并行传输多个资源。可以很好的利用大带宽。

http2协议通过使用静态表和动态表以及哈夫曼编码进行标头压缩,在不牺牲http协议的无状态特性的前提下有效减少了重复信息占比。而且随着访问次数增多收益更加明显

HTTP2协议因为在同一个连接上实现多路复用,那么如果想要终止一个请求的话,就不能通过断开连接了,因为可能同时还有其他的stream在传输。http2提供了RST帧来实现立刻终止一个未完成的stream。

除此之外,http2使用二进制传输协议,大幅减少传输数据量,而且http2支持消息优先级,可以对重要的资源优先传送例如一个页面上css的优先级要高于图片,这样浏览器可以更快的渲染整个框架出来。最重要的是http2兼容http/1.1的语义,仅在应用层做改动,这也使得http2的推广普及变得容易得多,而网站部署了http2之后对访问速度也能带来明显的提升。

http2协议存在的一些问题

尽管http2协议已经相当强大,但是仍然存在一些问题,就是因为http2协议仍然是基于TCP协议之上的应用层协议,就不得不继承TCP协议的优点和缺点。例如TCP协议的队头阻塞问题还有建立连接成本过高的问题。队头阻塞是因为TCP协议要保证顺序性,在多个流并行传输的情况下,sequence number小的报文如果丢失,那么后面的报文即便到达对端也不能提供给应用层使用,必须要前面的报文到达成为一段连续的报文才能给应用层使用,从而影响不相关的stream的传输。建链成本高是因为在当前移动互联网的场景下,我们切换wifi、4G切换基站就意味着我们的ip、端口的变化,这样标志着一个TCP连接的四元组发生变化,从而需要重新建立连接。这本身就是一个消耗,而在tcp之上还有TLS/SSL握手,又增加一层消耗。 新建立连接之后为了避免网络拥塞又要重新进行慢启动就不能有效利用带宽。这些问题表示着TCP不能很好的解决移动互联网的问题。

而http3基于UDP,天生就没有连接的概念,进一步的http3通过connection ID实现连接迁移,就是说ip、端口变归变,但是在应用程序没有退出的情况下,就能保证在应用层上的connection ID不变,从而保证是同一个会话,就不需要从头再来,继续传输。

搭建Nginx HTTP3服务器

下面我们正式介绍使用nginx搭建http3服务器,以及抓包分析http3协议格式。这里只是粗略介绍一下搭建过程,其实过程非常劝退,问题不断。

Clone nginx-quic分支的代码

hg clone -b quic https://hg.nginx.org/nginx-quic –insecure

编译google boringssl

gcc需要升级到gcc8以上,用来编译boringssl,这个编译时间非常长,我自己的4核心机器编译了将近两个小时之久。

编译nginx

./auto/configure –prefix=/usr/local/nginx-http3 –user=work –group=work –with-debug –with-http_v3_module –with-cc-opt=”-I /root/boringssl/include/” –with-ld-opt=”-L /root/boringssl/build/ssl -L /root/boringssl/build/crypto”

添加上http3的模块,其他的模块看自己需要安装。

配置nginx

需要有一个证书,我懒得重新搞证书,就把自己网站证书部上去然后改hosts临时访问到测试机上。然后需要添加一个header就可以了。

访问HTTP3

我下载了Chrome canary,也开启了quic选项,但是不知道为什么还是走的TCP协议,无奈又想编译一个curl,不过过程中还是遇到很多问题,最后找到一个支持http3的docker镜像用来测试。只能用tcpdump抓包用wireshark看。访问方式:curl –http3 https://www.starbugs.net:8443

抓包分析

将tcpdump保存的pcap文件用wireshark打开,可以看到当前版本是基于draft-27草案的版本,最关键的就是有一个源连接ID和目的连接ID,这是实现连接迁移的关键。

留下评论