闷棍暴打面试官HTTP3-上篇

前言

据悉今年诺贝尔奖揭晓, 量子力学再次登顶!量子通信也取得新进展,让人们对未来的生活充满期待。 如今网络通讯就像水一样, 把所有陆地连接起来,网民在各个论坛里吹水,学生在网络上水作业,甚至发达国家程序员,借助网络雇佣他人来水工作。

张大胖看着屏幕的控制台上统计了, 几十GB的下载流量,陷入沉思,怎么不到一个月用了这么多带宽? **以前车马很慢,一晚只够下一部高清影片。**现在一晚上可以下几十部,而且网费也低到离谱,网速却比从前快了巨多倍,生活变得索然无味。

如果把网络比作水,那么互联网公司其实是水利公司,它们给网民供应内容,而内容由地下水管运输,水管的材质有HTTP, UDP 等,而网民使用的设备就像"水龙头",比如Web牌水龙头用来接收HTTP/UDP的内容,Game牌水龙头用来接收UDP的内容,Email牌水龙头用来接收SMTP的内容,我们今天的主题是 HTTP3水管,与2012年发布一个草案的old money HTTP2 水管不同, HTTP3 是财大气粗 Google 提议的 new money, old money的目前仍然是网民使用的HTTP主流通讯协议, 本文中心思想是 new money是如何练成的。

闷棍暴打面试官HTTP3-上篇_第1张图片

Nginx升级HTTP3

QUIC(Quick UDP Internet Connections)是 Google 推出的一个项目,旨在降低基于 TCP 通讯的 Web 延迟。QUIC 非常类似 TCP+TLS+SPDY(Google曾经废弃的HTTP2提案) ,但是基于 UDP 实现的。它是HTTP/3 的基础协议。

2015 年,Google 将 QUIC 引入负责维护互联网协议的标准组织 IETF,并且 IETF 一直在对 QUIC 进行改进,目前有两个相似但不同的 QUIC 协议:Google QUIC 与 IETF QUIC。Chrome 中使用的是 Google QUIC,同步地 Google 也在参与 IETF 对 QUIC 的改进,发展到现在最新的 Google QUIC 版本 Q050 与 IETF QUIC 有许多相似之处,不过大多数 Chrome 用户通常无法与 IETF QUIC 服务器进行通信。
闷棍暴打面试官HTTP3-上篇_第2张图片

Nginx-quic 项目是基于 IETF QUIC 标准实现的 NGINX http3 支持, 目前是作为NGINX的开发分支存在, 下面介绍一下如何基于该项目将网站升级为HTTP3.

Docker OCI容器升级

推荐nginx-quic镜像

https://hub.docker.com/r/dasskelett/nginx-quic

  • 演示版本
    • my mac 10.15
    • Docker Desktop 4.12.0 (85629)
    • Docker version 20.10.17, build 100c701
    • OCI nginx-quic 1.23.1
    • OCI OS Archlinux

Nginx 配置迁移

# copy 原先的 nginx.conf 文件升级配置
vim nginx.conf

nginx.conf 在原有配置上自定义**(注意 TODO行)**

# 更多配置请查看官网 https://quic.nginx.org/readme.html
server {
        listen       443 ssl http2; 
        listen       [::]:443 ssl http2;
        listen       443 http3 reuseport;  # TODO add new config
        listen       [::]:443 http3 reuseport;  # TODO add new config

        server_name  localhost;

        ssl_certificate      cert.pem; # TODO http3 quic协议必须使用 tls
        ssl_certificate_key  cert.key; # TODO http3 quic协议必须使用 tls

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_protocols        TLSv1.3 TLSv1.2; # TODO replace default config 
        ssl_ciphers          HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;
        # TODO add new config
        ssl_early_data on;

        access_log   /var/log/nginx/access.log quic;

        location / {
            # TODO replace default config 必须使用该配置才能全站HTTP3成功. 后面会重点讲这个配置. 
            add_header alt-svc 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"';
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }

创建容器

# 确定配置文件升级完成, 本demo只提供MVP例子。 至于log目录/html目录/php扩展目录/tls证书目录, 请自行查看 layer 挂载.
docker run -d --name nginx-quic -p 80:80 -v ./nginx.conf:/etc/nginx/nginx.conf  -p 443:443/tcp -p 443:443/udp  dasskelett/nginx-quic:latest

检查nginx-quic容器是否运行成功

docker ps -a -f "name=^nginx-quic" --format="{{.Names}}"   

nginx-quic # 能查到说明运行成功

CentOS 升级

如果CentOS Nginx 要升级HTTP3, 我们有两种方式

1.将编译环境升级然后编译新版本Nginx

2.yum 安装 nginx-quic 版本进行升级 (推荐)

  • Nginx编译环境升级

    • 参考文章: https://zhuanlan.zhihu.com/p/345660441
    • 物料清单
      • cmake3.0以上
      • perl5.32以上
      • Golang1.15以上
      • gcc10.2以上
      • boringssl1.10.1以上
    • 缺点: c++编译时间慢长, 环境配置繁琐
  • yum 安装 nginx-quic (推荐)

    • 参考文章: https://www.mingilin.com/2020/11/06/centos/centos-nginx-quic/
      • 注意看评论, fix了一些实践会出现的问题
    • 物料清单
      • epel-release
      • centos-release-scl
      • yum-plugin-copr
      • nginx-quic
    • 缺点: yum 安装太方便了, 不用编译, 享受不了原汁原味的C++编译体验.

    nginx 与 nginx-quic 不能共存,注意备份数据

测试是否升级成功

开启浏览器HTTP3支持

火狐浏览器版本90+以上访问:about:config 推荐使用火狐浏览器测试, 对本地tls证书以及HTTP3协议友好.

启用:network.http.http3.enabled

Chrome 浏览器版本92+以上访问:chrome://flags

启用:enable-quic

1.火狐浏览器, F12 network, 如何显示HTTP3 则为成功.

闷棍暴打面试官HTTP3-上篇_第3张图片

2.使用第三方网站 http3check.net 测试网站的http3详细信息
闷棍暴打面试官HTTP3-上篇_第4张图片

将子域名与端口转发升级为HTTP3

子域名目前笔者没有实验成功, nginx-quic 443 udp 端口不能通用, 可能因为 beta 版的原因.

端口转发可以参考上述配置升级, 以浏览器访问为主的静态页面可以尝试HTTP3, 中间件不建议升级.

IETF QUIC 与 Google QUIC 杂谈

闷棍暴打面试官HTTP3-上篇_第5张图片

图片来源 IETF 官网: https://datatracker.ietf.org/doc/draft-ietf-quic-transport/18/

nginx-quic 项目处于 beta 阶段, 属于是快速迭代阶段, 重构了很多语法糖, 也停止兼容了老的HTTP3草案, 最新版本配置与官网文档配置有差距。 几乎所有浏览器没有默认支持 http3,http3是Google http2时代一个被否定的草案, 又改了一点推出了HTTP3, 已经被 IETF委员(http 协议权威机构)会官方认定。

目前由Google提出的HTTP3协议, 基本上已经在Google自家的生产环境跑了, 但是其他厂商支持意愿从图上看不是很强烈, 毕竟委员会也是由各大公司派人组成的,而且涉及到很多软硬件厂商的利益, 扯皮是少不了的。 如果HTTP3不能成为主流的话, 服务器升级后, 客户端不升级只能接着用HTTP2, 奇怪的是中文互联网对HTTP委员会推出的HTTP3协议接受程度出奇的低。

了解更多: https://hungryturbo.com/HTTP3-explained/quic/%E5%8D%8F%E8%AE%AE%E8%BF%9B%E5%B1%95.html#iefe

HTTP2 VS HTTP3

网络模型对比

闷棍暴打面试官HTTP3-上篇_第6张图片

从图上与官网得知

  • HTTP3与HTTP2 在网络层以下都是一致的.

  • HTTP3的QUIC协议 将TCP与UDP以及TLS作为必需项,而不是可选项.

  • 在应用层协议上HTTP3要高于HTTP2协议, 如果客户端不支持HTTP3特性, 则无法使用HTTP3, 而支持HTTP3后仍然可以向下兼容.

  • 无论是否开启 HTTP3 都需要开启TCP端口.

  • 在QUIC中,数据流由传输层本身提供,而在HTTP/2中,流则在HTTP层完成。

    • HTTP/3基于QUIC设计,QUIC是一个自己处理数据流的传输层协议。
    • HTTP/2基于TCP设计,因此数据流在HTTP层处理。
  • QUIC 就是HTTP3的核心协议, HTTP的前两个版本并没有翻天覆地的升级, 而HTTP3协议则基于QUIC颠覆了以往以TCP为核心的HTTP协议。

性能对比

在相同丢包率的条件下,HTTP/3 和 HTTP/2 性能测试对比如下

测试环境:服务端(HTTP/3 with cubic & HTTP/2 with bbr)、客户端(cubic)

闷棍暴打面试官HTTP3-上篇_第7张图片

闷棍暴打面试官HTTP3-上篇_第8张图片

闷棍暴打面试官HTTP3-上篇_第9张图片

Chromium 团队表示,其发现 IETF QUIC 的性能优势特别高,使得 Google 搜索延迟减少了 2% 以上,YouTube 的重新缓冲时间减少了 9% 以上,PC 客户端吞吐量增加了 3% 以上,移动设备的客户端吞吐量增加了 7% 以上,因此宣布 Chrome 即将引入对 IETF QUIC h3-29 版本的支持。

国内因G-F-W 防火墙 UDP屏蔽的原因, 导致内网测试与外网测试结论不一致, 国内互联网厂商一般自定义HTTP3协议实现, 仍然使用TCP作为核心协议, 具体参考: https://github.com/wangyu-/udp2raw/blob/unified/doc/README.zh-cn.md

稳定性对比

下图表示 HTTP/2 和 HTTP/3 多路复用两个请求时,数据包丢失及其影响

(请求及其相关的响应分别为深蓝和浅蓝色)

HTTP/2 多路复用 2 个请求。响应被分解为多个数据包,一旦一个数据包丢失了,两个请求都被阻止。

HTTP/3 复用 2 个请求。虽然浅色的数据包丢失了,但是深色的数据包传输得很好。

QUIC可以保证单个数据流的有序交付,但是多个数据流可能会乱序。这也就是说单个数据流的传输是按序的,但是多个数据流中接收方收到的顺序可能与发送方的发送顺序不同。

举个例子:服务器传送流A和B到客户端。流A先传输,然后是流B。在QUIC中,丢包只会影响该包所处的流。如果流A发生了丢包,而流B没有,流B将继续传输直到结束,而流A将会进行丢包重传。但在HTTP/2中这不可能发生。

如下图所示,连通两个QUIC端点的单一连接中的黄色与蓝色的数据流。它们互相独立,所以可能乱序到达,但是每个流内的信息一定是按序可靠到达的。

闷棍暴打面试官HTTP3-上篇_第10张图片

更多特性了解: https://hungryturbo.com/HTTP3-explained/quic/QUIC%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86.html

客户端/服务器兼容对比
  1. 客户端
    1. 设备客户端
      1. Google Chrome 配置支持,需要开启HTTP3
      2. Firefox 配置支持,需要开启HTTP3
      3. Safari 配置支持, 需要开启HTTP3
      4. IOS15 支持HTTP3
    2. 编程语言内置客户端
      1. Java库 Kwik是Java中协议的客户端实现。
      2. C/C++库 Microsoft’s MsQuic/Facebook’s mvfst等
      3. GoLang库 req 现已正式支持 HTTP3!
      4. RUST库 quiche的http3-client/Cloudflare’s quiche
      5. Node.js库 Node.js QUIC
      6. Python库 aioquic
  2. 服务器
    1. 代理服务器
      1. nginx-quic分支支持HTTP3
      2. Caddy支持HTTP3
      3. OpenLiteSpeed支持HTTP3
  3. Http2 绝大多数客户端与服务器都支持.
市场占有率对比

闷棍暴打面试官HTTP3-上篇_第11张图片

闷棍暴打面试官HTTP3-上篇_第12张图片

报文分析

浏览器Network报文分析

以Firefox浏览器控制台抓包为例。

请求头原始报文

GET / HTTP/3
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11.44; rv:106.0) Gecko/20100101 Firefox/106.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Alt-Used: localhost
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Pragma: no-cache
Cache-Control: no-cache
TE: trailers

客户端请求没有先去发一个询问是否为HTTP3的option方式请求, 而是直接发送HTTP/3协议, 客户端是如何知道当前服务器支持HTTP3的呢?

HTTP/3 200 OK
server: nginx/1.23.1
date: Mon, 31 Oct 2022 05:15:48 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 05 Oct 2022 10:02:59 GMT
etag: "633d5653-267"
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
accept-ranges: bytes

alt-svc字段是HTTP3的重要响应头。

Alt-Svc 全称为“Alternative-Service”,直译为“备选服务”。该头部列举了当前站点备选的访问方式列表。一般用于在提供“QUIC”等新兴协议支持的同时,实现向下兼容。

Alt-Svc: clear
Alt-Svc: ; ma=
Alt-Svc: ; ma=; persist=1
  • 使用分号隔离的访问方式列表,格式形如:=":"。这里的应当是一个有效的 ALPN 标识符。

  • 可选

    当前访问方式的有效期,超过该时间后,服务端将不保证该访问方式依旧可用,客户端应当重新获取更新后的 Alt-Svc 列表。单位为秒,默认值为 24 小时(86400)。

  • persist可选

    可选参数,用于标识当前访问方式在网络环境改变时或者会话间始终保持。

更多细节: https://hungryturbo.com/HTTP3-explained/quic/HTTP3.html#%E4%BD%BF%E7%94%A8alt-svc%E8%87%AA%E4%B8%BE

Wireshark报文分析

闷棍暴打面试官HTTP3-上篇_第13张图片

  • QUIC 流程
    • 第一次请求的探测阶段, 发送的还是tcp链接, 之后建立一个连接
    • 协商安全的TLS连接
    • 使用QUIC UDP数据流
  • 第N次访问HTTP3网站时, 并没有先走TCP握手, 而是直接使用 QUIC协议的0-RTT建立连接.
    • QUIC 中的 0-RTT 功能允许客户端在握手完成之前发送应用程序数据。这可以通过重用来自先前连接的协商参数来实现。为了实现这一点,0-RTT 依赖于客户端记住关键参数并向服务器提供允许服务器恢复相同信息的 TLS 会话票证。
    • QUIC允许客户端在0-RTT的情况下直接携带数据。这使得客户端能尽早向对方传送数据,当然也使得服务器能更快地发回数据响应。
    • QUIC提供了0-RTT和1-RTT的连接建立,这也就是说QUIC在最好的情况下不需要额外的往返时间便可以建立新的连接。两者中更快的是0-RTT,仅在在两个主机之间建立国连接且缓存了该连接的秘密时可以使用。
  • HTTP3网站每次访问都会有两个重复的DCID, 如同之前提到的黄蓝双线,HTTP/3 复用 2 个请求。虽然e6a786的数据包丢失了,但是000000135f95的数据包传输得很好。

Tip HTTP3的实用价值

对国内互联网来说没有实用价值, 国内大厂自研的XQUIC/TQUIC等均没有被浏览器检测为HTTP3协议, 可能是没有全部部署应用, 背后的原因令人暖心.

内网系统或者被代理服务器可以尝试升级, 不推荐代理服务器升级HTTP3. 不推荐在国内使用UDP作为HTTP3核心协议.

下篇将讲解HTTP3 Java库 Kwik 的实现以及QUIC协议全报文详细分析, 帮助大家理解与构建自己的QUIC协议.

你可能感兴趣的:(公众号,udp,java,面试,http,quic)