QUIC/HTTP3 协议简析
从 HTTP 的进化历史讲起,细说使用协议的变迁,了解原因发现问题,解码 QUIC 在 HTTP3 中的支撑作用,共同探讨 HTTP3 的未来。
HTTP、HTTP2 和 HTTP3
先和大家来回顾一下 HTTP 的历史,看看 HTTP3 相比 HTTP、HTTP2 都有哪些改进和升级的地方。
HTTP VS HTTP2
多路复用:多路复用时,多文件传输有时只需维护一个 TCP 连接。如果是 HTTP1 协议下,每份资源的传输对应一个 TCP 连接,一般最多只能开启 6 个 TCP 连接来传输多路数据,后续每增加一个新链接就会因为拥堵问题卡死,进而导致整个进程无法运行。因此HTTP/2解决了 HTTP 的队头阻塞问题。
头部压缩和 Server Push:HTTP2 会通过 HPACK 做头部压缩。同时 HTTP2 是二进制协议,在解析上相比基于文本的 HTTP解析效率上有所提升,并且 HTTP2 还增加了 Server Push。
在 TCP 下,依然无法解决延迟问题,比如为防止初始阻塞而引入的慢启动;TCP 队头阻塞,比如由于发生丢包,整个连接涉及的传输数据都需要重传而引起的阻塞。
尽管 HTTP2 相比 HTTP 已经有了改进的地方,但是如果你有 2% 的丢包率,那 HTTP2 在性能上就没有优势了。
上图是造成 TCP 队头拥塞(Head of line blocking)的原因。HTTP2 协议是基于 TCP 的,但是 TCP 本身是无法解决队头拥塞,为什么呢?因为 HTTP2 会把一次传输所有的文件都放在一个 TCP 连接中,只要这个 TCP 中发生一个丢包,连接就必须重新建立,之前所有传输内容进行必须重传,从而造成拥塞。
HTTP3 VS HTTP2
HTTP3 本质不是对 HTTP 协议本身的改进,它主要是集中在如何提高传输效率。上图是相比 HTTP2 而言 HTTP3 提升的点:
HTTP3 使用 stream 进一步扩展了 HTTP2 的多路复用。在 HTTP3 模式下,一般传输多少个文件就会产生对应数量的 stream。当这些文件中的其中一个发生丢包时,你只需要重传丢包文件的对应 stream 即可。
HTTP3 不再是基于 TCP 建立的,而是通过 UDP 建立,在用户空间保证传输的可靠性,相比 TCP,UDP 之上的 QUIC 协议提高了连接建立的速度,降低了延迟。
通过引入 Connection ID,使得 HTTP3 支持连接迁移以及 NAT 的重绑定。
HTTP3 含有一个包括验证、加密、数据及负载的 built-in 的TLS安全机制。
拥塞控制。TCP 是在内核区实现的,而 HTTP3 将拥塞控制移出了内核,通过用户空间来实现。这样做的好处就是不再需要等待内核更新可以实现很方便的进行快速迭代。
头部压缩。HTTP2 使用的 HPACK,HTTP3 更换成了兼容 HPACK 的 QPACK 压缩方案。QPACK 优化了对乱序发送的支持,也优化了压缩率。
为什么选择 QUIC
从图上可以看到 QUIC 协议层就实现了可靠的数据传输,拥塞控制,加密,多路数据流。
至于 QUIC 为什么使用了 UDP 的问题,在了解这个之前,我们需要先知道一个事情。频繁的用户态和核心态切换会效率问题。理论上说,将应用层的东西迁移到内核从而提升效率是可行的,但是这么做会影响操作系统的稳定性。另一方面,我们可以选择将这部分内容迁移到用户空间。比如目前流行的 DPDK,当网卡将数据包传输过来时,它是绕过内核在用户空间进行控制和应用。目前又拍云的 DNS 就进行了这样的处理,让又拍云的整体效率提升了5-10 倍。
接下来我们来正式说一下 QUIC 为什么使用了 UDP 的问题,是因为以下几点:
避免 ossification(僵化):QUIC 协议加密负载,也是避免协议僵化一种方式,比如当中间层处理 UDP 数据时,只需要按照数据包的方式去处理即可,不需要去关注内部层的具体信息。
放弃改进 TCP 本身
创新方向:QUIC 是由谷歌提出的,所以 UDP 是以浏览器为出发点,从协议、从浏览器方向来进行创新。
TLS 1.3 Vs TLS 1.2
TLS 1.3 跟 1.2 的一些提升主要有上图几点,大家可以大致看一下:
TLS 1.3 采用了新的加密套件
TLS 1.3 定义了一些新的证书类型以及秘钥交换机制。在 TLS 1.3 你不再需要去特别指定,它可以根据秘钥套件配件进行证书类型的自主推导。
QUIC 存在的问题
接下来说一下 QUIC 目前存在的问题。
首先是因为这些年性能的优化提升都针对 TCP ,使得 UDP 性能没有任何改进。当然随着 QUIC3 的发布,相信后续应该会有相对的投入。
其次是安全问题,也就是反射攻击,即伪造原地址。这个指发送数据包时的原地址是伪造的,不是真正的地址,会引起放大攻击。原因是 QUIC 握手过程是不对称的,特别是第一次请求时,客户端只需要发送几个字节的信息到服务器,而服务器则需要把证书等很多东西返还给客户端,这个不对称的机会造成了放大。草案 27 定义了两个规则和机制来限制反射攻击:客户端发送Initial包,即第一个数据包时,其长度必须在 1200 bytes以上,不足部分用 Padding 帧填充,同时,当服务端不确定客户端可靠性时,可以发送 Retry 包要求客户端再次提供验证信息。
开源 QUIC 的实现
接下来我们简单说一下目前开源的使用情况:
quiche:这个是用 Rust 做的库,通过 Nginx 调用。google 自己的库也叫 quiche,C++写的。
ATS:Apache Traffic Server
golang:Caddy;
python+C,aioquic
微软msquic
开源 QUIC 的实现有很多,上面只是其中的一部分,同时我选择了quiche 和 aioquic 做了一些简单测试。
上图展示的是从 cloudflare 提供支持 HTTP3 的 curl ,可以看到这个返回的值就是 HTTP/3 200。其中 alternative service 段,指示为 h3—27,表示支持 http3 draft-27 的服务跑在 UDP 443 端口。这个 alt-svc 是 HTTP2 时代就存在,在 HTTP3 也持续使用,因为有些时候浏览器并不知道服务器是否支持 QUIC,所以通过 TCP 发起请求,确定有 H3 支持后,再通过 UDP连接。
这个是 HTTP2 的,目前可能是因为本身库的问题,使用 curl 打不开谷歌,但是从信息上可以看到 27、25 这些都是支持的。
如何部署以及达成 HTTP3 的 QUIC 实现
目前主要有两种方式来实现,一种是代理,第二种是通过 Nginx。
腾讯是通过整合到 Nginx 利用它来实现框架的。同时因为 QUIC 每一条请求的含有头的数据都会经过加密,腾讯有一个单独的硬件加密群,如果你使用腾讯,那么你所有的加解密都会通过他们的硬件来加速。
从腾讯这个可以看出加解密部分有着很可观的 CPU 占用率,如果后续所有的请求都是通过 HTTP3 来进行的话,在提升这块占用率上需要未雨绸缪。当然就像前面提到的 DPDK,也就是把数据丢到 FPGA 内去加解密是一个可以考虑的解决方案。
通过代理来实现的这种方式,目前官方暂时还没有消息。我可以像 cloudflare 那样,先在外面进行整合,然后再讲整合链接转到 Nginx 内。
又拍云目前有 LBS 和 Marco ,这个是因为 LBS 只认 TCP/UDP,它看不到 HTTP。也就是我们做了一个负载均衡的集群,通过这个集群在转到 Nginx 上。而使用 UDP 则相当于已经走过了一个四层的负载均衡,那么后续可以尝试将 QUIC 的基线提取出来使用,在代理上做加解密,从而提高效率。
推荐阅读
QUIC/HTTP3 协议简析的更多相关文章
- DNS使用的是TCP协议还是UDP协议简析
DNS使用的是TCP协议还是UDP协议简析 DNS同时占用UDP和TCP端口53是公认的,这种单个应用协议同时使用两种传输协议的情况在TCP/IP栈也算是个另类.但很少有人知道DNS分别在什么情况 ...
- Https协议简析及中间人攻击原理
1.基础知识 1.1 对称加密算法 对称加密算法的特点是加密密钥和解密密钥是同一把密钥K,且加解密速度快,典型的对称加密算法有DES.AES等 ...
- HTTP协议--简析
HTTP--超文本传输协议(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是所有的www文件都必须遵守的标准. 要想成为优秀的web开发人员,必须熟悉H ...
- TCP 协议简析
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的.可靠的.基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接.它是个超级麻烦的协议, ...
- mysql协议简析
前言 如果要在命令行中连接mysql,最常用的便是 mysql -u root -p 这样指定用户名和密码 当然还可以使用远程连接 mysql -h 127.0.0.1 -u root -p 还有一种 ...
- STUN协议简析
http://blog.csdn.net/mazidao2008/article/details/4934257 ——————————————————————————————————————————— ...
- HTTP协议简析(二)
HTTP响应也包含四部分内容: 响应行: 协议版本:HTTP/1.1 状态码:200 状态描述:对状态码的说明 响应头:用来规范数据,常用的有: server:服务器信息 date:响应的时间 las ...
- http协议简析(一)
HTTP:hype-text transfer protocol,超文本传输协议,超文本(html)在网络间(电脑与电脑之间)传输过程中所遵循的一些规则. 两台电脑之间要实现数据传输的条件 1.两台电 ...
- DHCP协议简析
推荐这篇文章,原理及抓包都分析的很好: **推荐这篇文章,原理及抓包都分析的很好:** https://blog.csdn.net/andy_93/article/details/78238931 简 ...
随机推荐
- CVE-2020-0796永恒之黑复现POC EXP以及修复方案
描述: 北京时间3月12日,针对最新披露的SMB远程代码执行漏洞(CVE-2020-0796),微软官方发布了针对Windows 10/Server禁用SMBv3(SMB 3.1.1版本)协议压缩的安 ...
- Java实现 LeetCode 792 自定义字符串排序(暴力)
792. 匹配子序列的单词数 给定字符串 S 和单词字典 words, 求 words[i] 中是 S 的子序列的单词个数. 示例: 输入: S = "abcde" words = ...
- Java实现 LeetCode 747 至少是其他数字两倍的最大数(暴力)
747. 至少是其他数字两倍的最大数 在一个给定的数组nums中,总是存在一个最大元素 . 查找数组中的最大元素是否至少是数组中每个其他数字的两倍. 如果是,则返回最大元素的索引,否则返回-1. 示例 ...
- Java实现 蓝桥杯 算法训练 Bit Compressor(暴力)
试题 算法训练 Bit Compressor 问题描述 数据压缩的目的是为了减少存储和交换数据时出现的冗余.这增加了有效数据的比重并提高了传输速率.有一种压缩二进制串的方法是这样的: 将连续的n个1替 ...
- Java实现 LeetCode 706 设计哈希映射(数组+链表)
706. 设计哈希映射 不使用任何内建的哈希表库设计一个哈希映射 具体地说,你的设计应该包含以下的功能 put(key, value):向哈希映射中插入(键,值)的数值对.如果键对应的值已经存在,更新 ...
- Java实现 LeetCode 703 数据流中的第K大元素(先序队列)
703. 数据流中的第K大元素 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组n ...
- Java实现 LeetCode 559 N叉树的最大深度(遍历树,其实和便利二叉树一样,代码简短(●ˇ∀ˇ●))
559. N叉树的最大深度 给定一个 N 叉树,找到其最大深度. 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数. 例如,给定一个 3叉树 : 我们应返回其最大深度,3. 说明: 树的深度不 ...
- Java实现 蓝桥杯VIP 算法训练 数列
问题描述 给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是: 1,3,4,9,10,12,13,- (该序列实际上就是 ...
- Java实现 基础算法 百元买百鸡
public class 百元买百鸡 { public static void main(String[] args) { //母鸡 for (int i = 1; i < 33; i++) { ...
- 一张图说清楚Flink水印和Lateness
真传一句话,假言万卷书. Flink使用窗口与水印处理乱序问题,使用Latenss处理延迟问题,二者混合使用可以满足很多复杂场景的需求 当Watermark大于窗口结束时间时,会触发窗口内的元素进行计 ...