你听过HTTPS、HTTP2.0、SPDY,可是这些应用层协议都是基于可靠的传输层协议TCP来实现的。那么,基于高效的UDP协议有没有一种相对可靠的应用层协议呢?php
你听过HTTPS、HTTP2.0、SPDY,可是这些应用层协议都是基于可靠的传输层协议TCP来实现的。那么,基于高效的UDP协议有没有一种相对可靠的应用层协议呢?html
图1 why quic?nginx
What is QUIC?web
Quick UDP Internet Connection(QUIC)协议是Google公司提出的基于UDP的高效可靠协议。算法
说它高效,是由于使用了无链接的UDP而不是迭代周期更长的须要修改系统内核网络栈的TCP协议。
说它可靠,是由于将改进了的可靠TCP的协议特征用到了QUIC上。segmentfault
同时,也复用和改进了HTTP2的典型特征,譬如二进制分帧,多路复用,header压缩等。浏览器
图2 what's quic?缓存
出于HTTP的明文和没法验证服务器的真实性,在TCP的基础上引入了TLS协议,目前普遍使用的HTTPS是基于TCP+TLS协议,HTTP2也被主流浏览器默认支持TLS。安全
但对于创建链接的耗时而言,TCP自己就须要握手时延,而TLS协议为了使得客户端和服务器端在不安全的网络通讯中协商出后续安全通讯所需的加密私钥,更是要通过额外2次RTT(RoundTrip Time往返时间)服务器
图3 TCP+TLS建连过程
除了TCP创建链接过程,TLS握手过程要通过以下步骤:
一、客户端提供加密套件(算法)列表,版本等信息
二、服务器端提供本身的证书,选择的加密套件,非对称加密公钥(本身保留私钥)等
三、客户端提供本身的证书,用服务器公钥和加密套件加密的本身的私钥
四、服务端用保留的私钥解密客户端传来的加密私钥,获得的私钥即为后续加密传输使用的对称密钥,最后完成握手
此时,双方协商出了对称密钥。基于TCP+TLS的HTTP2建连过程结束,大约须要耗时200-300ms。
为了保证安全,QUIC也是加密传输数据的,因此在QUIC的建连过程当中也须要双方协商出一个加密私钥。但与TLS不一样,QUIC采用的加密算法仅须要一个RTT就能实现密钥交换,而且该算法也被用于目前正在草案阶段的TLS1.3协议。该就是Diffie-Hellman密钥交换算法。
图4 Diffie-Hellman算法
能够看到,客户端和服务端各自保留了本身的私钥a和b,经过交换各自的公钥B和A,以及基底G和很大的质数P,双方就能计算出相等的私钥S,这个S就是加密传输的对称密钥。
另外,根据离散对数的不可逆,即便拿到G,P,和质数B,也很难推导出私钥b(同理私钥a),也就保证了计算密钥的安全。
该过程对应到QUIC建连的过程当中以下图。
图5 1RTT建连
一、客户端发起Inchoate client hello
二、服务器返回Rejection,包括密钥交换算法的公钥信息,算法信息,证书信息等被放到server config中传给客户端
三、客户端发起client hello,包括客户端公钥信息
此时,双方各自计算出了对称密钥。QUIC的1RTT建连过程结束,平均只耗时100ms之内。
后续发起链接的过程当中,一旦客户端缓存或持久化了server config,就能够复用并结合本地生成的私钥进行加密数据传输了,不须要再次握手,从而实现0RTT创建链接。
协商升级
通常状况下,Chrome浏览器和服务器端协商使用QUIC协议要通过以下步骤:
一、客户端发出tcp请求
二、服务端若是支持quic能够经过响应头alt-svc告知客户端
三、客户端同时发起tcp链接和quic链接竞赛
四、一旦quic创建链接获胜则采用quic协议发送请求
五、如遇网络或服务器不支持quic/udp,客户端标记quic为broken
六、传输中的请求经过tcp重发
七、5min后尝试重试quic,下一次尝试增大到10min
八、一旦再次成功采用quic并把broken标记取消
其中,支持quic的alt-svc头部信息以下图示,ma为有效时间(单位秒),v为支持的quic版本信息。
图6 alt-svc头信息
研究过程当中发现,除了alt-svc header,http2.0下服务端还能够经过支持alt-svc frame来让客户端在第一次请求的时候就走新协议,比经过header让浏览器第二次才能请求新协议更高效,这个留给后续研究。
链接迁移
TCP使用四元组(源IP,源端口,目的IP,目的端口)来标识一条链接,当四元组中的IP或端口任一个发生变化了链接就须要从新创建,从而不具有链接迁移的能力。
而QUIC使用了connection id对链接进行惟一标识。即便网络从4G变成了wifi,只要两次链接中的connection id不变,而且客户端或者服务器能经过校验,就不须要从新创建链接,链接迁移就能成功。
改进的多路复用
在SPDY协议出现之前,每一个HTTP请求都须要创建一条TCP链接,那么若是但愿请求并行,就须要同时开启多条TCP链接(都是有建连代价的)。而大多数浏览器对于同一个域名能够创建的最大TCP链接数是有限制的,因此,若是超出限制,更多的请求资源是没法并行的。
SPDY协议以来提出的多路复用,是让全部请求基于一条TCP链接,解决了上述的问题但同时引入了新的问题——队头阻塞,若是某个资源的某个包丢失了,由于TCP是保证时序的,就会在接收端造成队头阻塞,TCP此时没法区分各个资源的包是否关联,所以会中止处理全部资源直到丢包恢复。
图7 基于TCP的多路复用
QUIC也有多路复用,可是QUIC是基于UDP的,UDP不须要保证包的时序,只会在接收包的时候对包进行重组,于是不存在等待丢包恢复的队头阻塞问题,这样某个资源的包丢失只会影响自身不会影响到其余资源的继续传输,因此是改进的多路复用。
图8 基于QUIC的多路复用
双级别流量控制
QUIC是多路复用的,多条stream能够创建在一条connection上,因此QUIC的流量控制不只基于单个stream,还基于connection。
stream级别的流控可以控制单stream的数据发送状况。另外,接收窗口的收缩取决于最大接收字节的偏移而不是全部已接受字节的总和,它不像tcp流控,不会受到丢失数据的影响。
图9 stream流控
若是知足(flow control receive offset - consumed bytes) < (max receive window / 2)
会触发WINDOW_UPDATE frame的发送来增大发送窗口大小。
图10 WINDOW_UPDATE触发前
图11 WINDOW_UPDATE触发后
connection级别流控算法和stream一致,各项数值是全部stream的总和。
connection级别的流控存在的必要是,即便作好了stream流控,但若是stream过多也会致使connection过分消耗带宽和系统资源;并且即便某一条stream过慢,其余stream依然能触发
connection级别的WINDOW_UPDATE,从而不会被影响。
图12 connection流控
拥塞控制
咱们知道TCP有多种拥塞控制算法,当遇到网络拥塞会经过减包等方式来避免网络环境恶化。可是,UDP自己是没有拥塞控制的,一旦不加约束的使用会致使侵占其余“守规矩”的网络协议的带宽。
因此,为了不上述状况,基于UDP的QUIC协议借鉴了TCP的一些优秀的拥塞控制算法,如默认使用Cubic,同时,为了不AIMD机制带来的带宽利用率低,采用了packet pacing来探测网络带宽。
思路是,QUIC会经过追踪包的到达时间来预测当前带宽的使用状况,以决定是否提升,保持或者减小发送包的速率来避免网络拥塞。
图13 packet pacing
丢包恢复
相似拥塞控制,除了基于TCP的一些丢包恢复机制,如:TLP,FACK。QUIC的丢包恢复也在一些方面作了改进。
好比:经过引入严格递增的sequence number使得计算RTT更加精确。更精确的RTT也意味更精确的RTO和超时重传机制。
还好比咱们知道TCP中有个SACK选项,该选项打开时用于记录传输过程当中一些没有被确认的数据的范围,便于后续定向重传多组丢失数据,而不是所有重传,因此更多的范围便于更多的选择重传,也意味着更少的重传包频率。但TCP最多支持3个SACK范围,而QUIC能支持255个。
除了上述基于TCP的改进的丢包恢复特性之外,早期的QUIC版本还有一个丢包恢复机制,就是FEC(Forward Error Correction),这个特性虽然目前处于正在改造阶段(可能会浪费带宽而且做用不是很明显),可是依然是一个有意思的解决方案。FEC的思路是经过在一组包(通常是10个)中,经过增长一个FEC包,并用FEC和每一个包进行XOR,若是一旦有丢包,那么将FEC包和其他包XOR,获得的FEC包就是那个丢包,因此一组包最多只能恢复一个丢包。
更多特性
除了上述的主要特性,QUIC还有一些其余特性,如:
● 经过header stream保证流顺序
● 底层保证链接持久
● 源地址令牌防止地址欺骗
● 握手时压缩证书避免放大攻击
在此不深刻研究,你们有兴趣能够翻阅Google相关的文档查阅。
业界应用状况
● Google超过50%的请求来自QUIC
● 目前Youtube有20%的流量来自QUIC
● 微博移动端全面支持QUIC协议
测试demo
● 客户端
最新版本PC Chrome(控制开启/关闭quic)
● 服务器
经stgw改造支持quic的nginx
● 页面地址(机器被回收,后续会更换机器供测试)
stgwquic.kof.qq.com/club/platfo…
stgwquic.kof.qq.com/club/platfo…
stgwquic.kof.qq.com/club/platfo…
● 网络
公司staffwifi
● 抓包工具
wireshark
● 效果对比
图15 HTTP1.1协议的页面
图16 HTTP2协议的页面
图17 QUIC协议的页面
图18页面请求20个,大小2MB
图 19 页面请求15个,大小465KB
● 客户端支持
X5内核团队(移动端)
依赖用户浏览器支持QUIC状况(PC端)
● 服务端支持
STGW团队
● 业务自身
按照路径灰度,控制灰度策略
以上测试demo数据是基于公司良好的网络状况下测试获得的,在实际运用过程当中,你们可能更关心在复杂的网络环境下QUIC的表现。因而QQ会员团队经过灰度现网的一个页面来考察QUIC在现网的性能状况。
● 页面状况
Android日PV100w,页面大小95KB
总请求30个,其中主资源请求1个,CDN请求24个,其余请求5个
展现部分依赖php直出和js渲染
● 灰度状况
QUIC请求1个(php页面主资源),HTTP2请求29个
● 灰度策略
客户端天天放量,对比灰度过程当中页面主资源的HTTP2和QUIC的性能数据
● 灰度效果
图20 QQ会员页面QUIC灰度状况
● 效果说明
由于建连依赖于1RTT和0RTT机制,使得QUIC建连平均耗时仅需46ms,比HTTP2的225ms减小180ms左右。
因为目前灰度量只占到总请求量的10%,所以更严谨的性能对比数据有待进一步提升灰度范围,以上仅做现阶段参考。
但依然能够看到QUIC在现网环境整体表现忧于HTTP2。
在实践QUIC的过程当中,咱们也遇到了一些须要注意的问题。
● QUIC支持头部alt-svc的缓存机制面向整个域名
业务即便只在一个页面路径下加了支持头部(STGW能够是路径级别支持,X5只能是域名级别支持),浏览器也会根据头部的缓存时长做用于用户访问该域名下的其余页面,但STGW可能只支持了路径级别。因此灰度过程当中,尽可能使用有独立域名的页面。从而保证尽可能不影响其余页面的请求状况(虽然QUIC请求失败会降级H2),尽可能减小ma缓存时间。
● 客户端对于QUIC的协商机制有待改善
在X5目前的实现机制中,不管如何首次请求都会基于HTTP2,后续才会尝试QUIC,但若是缓存时间设置的不够长(譬如1天),会使得用户通常1天内很难经过再次请求走到QUIC。因此,目前咱们作的是推进X5在请求时候让白名单连接直接尝试QUIC。同时,避免缓存时间随着用户退出手Q而失效,推进让其落地。
● 目前客户端基于X5的QUIC与一些基于缓存和预加载的页面秒开方案冲突
若是大家的页面是基于X5内核,可是使用了上述相似的技术,那么存在一个问题是本来直接经过X5走QUIC协议的页面不直接走X5了,而是基于你当前方案的缓存或者自定义的webview请求方式。因而经过统计数据会发现QUIC的请求量不多,由于上述技术目前还不支持QUIC协议。当前的作法是在QUIC和该方案中二选一。
● CDN请求灰度须要自支持
因为CDN请求不基于STGW代理,于是须要CDN团队针对业务方域名灰度支持,目前CDN总体处于运营商灰度QUIC阶段。在此以前若是须要灰度CDN请求就须要业务方本身处理转发。
● 运营商的Qos影响须要更完善的上报数据进行评估
使用QUIC协议比较担忧的一个问题就是在网络质量差的状况下运行商Qos会对其产生怎样的影响。从目前总体的统计数据,包括慢速用户占比等状况来看,影响不是很大。后续须要推进各方完善上报监控该状况下耗时。
● 和X5团队一块儿解决首次请求必走HTTP2请求问题
● 和X5团队一块儿解决alt-svc缓存有效期落地问题
● 和终端团队一块儿解决秒开方案下Webview对QUIC的支持,争取既能使用QUIC协议又能使用秒开方案
● 配合CDN团队验证QUIC扩大灰度的支持效果
● 推进各方更细粒度的数据统计完善
参考资料
QUIC Crypto Adam Langley Wan-Teh Chang
fasterdata.es.net/host-tuning…
HTTP over UDP: an Experimental Investigation of QUIC
QUIC FEC v1 Author: ianswett@google.com Last Updated: 2016-02-19
Understanding QUIC wire protocol
IETF93 QUIC BarBoF: Congestion Control and Loss Recovery
QUIC: Performance and Security at the Transport Layer
WeTest压测大师——为了帮助开发者发现服务器端的性能瓶颈,腾讯WeTest开放了压力测试功能,经过基于真实业务场景和用户行为进行压力测试,实现针对性的性能调优,下降服务器采购和维护成本。
目前压测大师服务了包括王者荣耀、QQ飞车手游、QQ炫舞手游等多款高星级手游, 也服务了QQ、NOW直播、摩拜单车、企鹅FM等明星产品。
目前WeTest压测大师对外开放中,点击连接:wetest.qq.com/gaps 便可使用。
若是对使用当中有任何疑问,欢迎联系腾讯WeTest企业QQ:800024531