Hello quic

背景
http1.x的不足,从1999年诞生的http1.1,通过近20年的发展,已经有许多丰富的功能,至今也是web世界的主要应用层协议,在电商,内容互联网,云存储网络上都有大范围的应用,1.1以前的版本很少说了,主要描述下1.1的在现代网络中的不足,这也是开启http3.0时代的一个重要因素。
http1.1一个典型的请求格式是:
User-Agent: PostmanRuntime/7.15.0
Accept: */*
accept-encoding: gzip, deflate
Connection: keep-alive
响应格式:
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/html;charset=UTF-8
Content-Length: 606
或者是chunk的模式
可是,看一个了例子:
这些指标的说明: developers.google.com/web/tools/c…
这个是http1.1的golang延迟测试,停滞时间比较长,主要缘由仍是http的请求是串行的。那后边有个http2的改进,看下效果: http2.golang.org/gophertiles…
主要优化点仍是在http2的编码格式,头部压缩,cookie的映射,多路复用提高的,主要仍是最后一条,可是依然有一个问题,若是是在网络条件ok的状况下是没有明显问题的,使用http2也能由于多路复用达到缩短用户请求时间的需求,可是若是是网络环境较差的状况下呢,看个例子:
http2依然也是有严重的排队问题,这里的网络设置是4G网络,网络可靠性设置的是90%,模拟网络不稳定
http1:从时长上看,虽然HTTP1的时长不必定就比http2的长了,图片也加载完了,也没有出现断网的状况,也就是说网络相对http2来讲没那么拥塞。
  • 究其缘由,网上也有不少的解释,我的理解主要仍是这里的多路复用是用应用层的实现,在传输层并无解决tcp的队头阻塞隐患,由于tcp的可靠性是经过有顺序的序号且按照序号顺序处理的,并且拥塞控制可能也不是完美的适合弱网,具体的这里的详细分析能够参考: mp.weixin.qq.com/s?__biz=MzU…
  • 总结下http基于tcp的一些问题:
  1. TCP链接耗时,三次握手,优化的TFO(具体参考: tools.ietf.org/html/rfc741…) 更新也是比较困难的。
  1. TLS1.2链接耗时,至少须要一个RTT
  1. TCP的header没有被校验
  1. http2的多路复用在某种状况下回加重head of line的问题
  1. 重复包确认致使的RTT误判


  • 因此google率先作了一些尝试并取得了必定的成功,2009年SPDY开始开发和设计,在2012年IETF小组也参考了SPDY设计了本身的QUIC协议,并但愿得到推广,2016年Google也中止对SDPY的更新,quic的出现一个重要的能力就是能在上边那个弱网状况下作的更好。下边说的quic都是IETF的quic,若是了解http2会发现不少设计例如frame,stream和http2很类似。
quic协议特性分析
协议定义细节
header
header可进行压缩处理,使用QPACK做为压缩算法,搭载的流类型是HEADER STREM,其格式是普通的key-value,没有像http规定的那种固定格式,可搭载的key是HEADER FRAME中容许出现的。
stream
这个概念能够理解为一个http的请求、响应,多个stream能够并发的在一个connection上执行,它们之间没有顺序关系,stream这个概念在传输层上,应用层不关心,stream按照搭载的数据用途不一样分为多种类型,有control stream,push stream,request stream。这里说明下,push stream就是服务端->客户端的流,不管是被动响应仍是主动推送的。stream内部就是多个frame组成的本次请求,不过这里的frame不是http层面的frame,它是传输层本身用来管理一个stream上的数据用的,作buffer, 排序,输出一个可靠传输的数据流。
frame
frame是一个http layer的帧,全部的frame都是搭载在stream上的,不一样类型的frame可能容许出现的stream不同:

全部的frame都是以下格式:
type是表明这个frame的类型,值是一个有符号整数,length表明的是frame payload的数据长度,值也是一个有符号整数,frame payload就是按照type描述的frame进行存储数据的,例如是一个headers的frame的话就要按照header的格式定义存放,必须是可识别的格式,不然认为是HTTP_MALFORMED_FRAME错误,或者在没有读取到结束符就无数据了也认为是出现该种错误的。
具体的重要的frame有:
DATA: 搭载二进制数据的帧类型,必须是HTTP request/response的数据若是出如今其它stream(control stream),就认为是HTTP_MALFORMED_FRAME。
HEADERS:做为quic的header block,只容许出如今requst/push stream上。
剩下的可看下draft-ietf-quic-http的RFC
http message处理
request的message能够在不发送彻底后服务端就发送完整的response message,一个stream上只能搭载一个request message,而response message能够在一个stream上有多个。

协议归协议,在实现的时候仍是要考虑现实问题,例如为了解决队头阻塞问题,虽然用了udp,可是TLS也有record的阻塞,因此,尽可能一个frame不大于MTU,这样每一个frame都是独立校验的,不会阻塞,
功能特性
减小TCP三次握手及TLS握手时间
1.传输层0-RTT创建链接
2.加密层0-RTT创建加密链接
拥塞控制灵活
虽然一些算法都是copy的tcp的可是与tcp不一样的是它的控制位置,tcp在网络协议栈上,拥塞控制对网络的稳定性(网络切换)和可靠性(丢包)比较敏感。同时在kernal中更新升级应用程序每每是痛苦且漫长的。
quic的改进的地方主要仍是增长了拥塞控制算法的种类,且热更新,应用能够根据自身状况进行动态调整,同时tcp包丢失后的重传致使packet numer重复的问题可获得了重视:
  • quic包重传示意图
  • stream视角的包重传示意图
同时,ack的时间计算更加精确,考虑了server端的处理时延。
在流量控制上,从两个方面触发,一个是stream的流量控制上,一个是从connection的流量控制上出发:
  • quic 流量控制示意图
解决head of line问题
  • tcp 可靠传输示意图


  • tcp TLS包丢失示意图

  • quic可靠传输示意图
如上图,若是有stream的包丢失了,那不影响其余stream的传输,并且,传输的基本单元packet,通常超过MTU,这样,加密的时候基于packet进行,尽可能避免了TLS的阻塞问题。
链接可迁移
quic的链接不是面向链接的链接,而是一个id标识,这样若是用户进行了网络切换了也能在这个链接上继续传输。而这样作相比直接用新的quic链接的优点是省去了TLS的握手。由于基于该链接的话是有CACHE的,在服务端上这个链接是可用的,没有发送Close的frame,根据协议说明,目前只支持failover的状况。
基于quic和http的性能对比
在网络wifi信号好的状况下:



在网络丢包,稳定性不佳的状况下:
由于charles好像不能代理quic,因此我这里使用的是mac的网络模拟工具:
quic的表现:

http2的表现:
参考
HTTP3的演化历程: www.infoq.cn/article/IgM…
quic协议原理分析: zhuanlan.zhihu.com/p/32553477
相关文章
相关标签/搜索