B站QUIC实践之路

QUIC协议快速建立连接、拥塞控制灵活、多路复用等特性为网络传输带来了不少收益,也更好的提升了用户的体验。哔哩哔哩高级工程师 王盛在LiveVideoStack线上交流分享中介绍了B站在QIUC研发与部署中的实践经验,LiveVideoStack对分享内容进行了整理。

文 / 王盛

整理 / LiveVideoStack

直播回放

&token=-tkUdxVX8Ti1r0cPh106AvZXQLOzrJs4N_7hHIksFNZBJ7OhUy3qsJbeBQgjkUbzjAk6Qj2pOAo

大家好,我是来自Bilibili的王盛,五年多来我一直从事网络协议和点直播系统的研发工作,加入B站后主要负责Bilibili的点直播系统开发,可以说见证了B站的点直播系统从零发展到目前TB级别的整个过程。接下来我将从以下四个方面为大家分享B站在QUIC协议上的技术探索,希望大家能通过此次分享了解更多QUIC特性与服务端架构技术细节。

1. 从Http1.1、Http2到QUIC

我们讨论QUIC协议一定先从HTTP协议出发。作为目前互联网上被使用最多的网络协议,HTTP经历了从1996年诞生到现在二十多年的发展,相对于早期的1.0、1.1版本,现在的2.0版本可以说发生了非常大的变化。据第三方机构统计,2015年HTTP/2版本的更新不仅加入了如二进制协议、多路复用、服务端推送等诸多新特性,更是实现了相对于HTTP/1近两倍的性能提升。

而我们今天讨论的QUIC协议其实就是所谓的HTTP/3,Google从提出QUIC协议以来一直想将其作为优化与替代现行HTTP协议的解决方案。从上图我们可以看出QUIC是完全基于UDP协议实现的,我们知道现在主流的两大互联网传输协议是TCP与UDP,前者连接可靠的数据传输而后者连接不可靠的数据传输;如果QUIC协议建立在UDP协议之上就需要实现一系列与TCP相似的数据传输操作如拥塞控制、数据重传、数据排序等,使得基于UDP的QUIC成为一种用户态的协议。目前TCP协议实现大部分功能都离不开内核,这就导致如果开发者希望修改调整TCP协议中的某一些特性与功能或根据需求进行定制化开发部署的难度非常大,尤其是涉及到内核改动的工作会带来不必要的开发成本;除了具备用户态协议的优势,为了实现更快的数据传输,QUIC也囊括了一些类似于TLS安全传输层的功能,为了提高兼容性QUIC也提供与之前HTTP2一样HTTP语义,从而实现在应用层程序方面良好的兼容性。

QUIC协议从诞生至今获得了不少厂家与企业的支持,也为这些企业带来了收益与回报。纵览整个行业,国外如Google搜索、YouTube视频、Akamai CDN等等都实现了对QUIC协议的支持,国内如腾讯云的负载网关、QQ空间、七牛直播云的直播推流等都在QUIC协议的帮助下实现了如0卡顿的直播推流等等技术提升,而B站的点直播CDN也实现了对QUIC的全面支持。QUIC为这些企业带来的收益同样不容小觑,如为Google搜索页面带来了5%的加载速度提升,使YouTube的视频卡顿率降低了30%;为QQ空间带来了10%的加载速度提升,帮助B站提升10%视频首帧的同时减小5%的卡顿,可以说极大提升了互联网产品的用户体验。

接下来我们将QUIC和TCP之间的性能与参数差异落实在用户体验层面,首先模拟用户同时使用分别基于QUIC与TCP的两个播放器播放同一个视频文件,理想环境下用户的直观感受是二者画面基本同步流畅;但如果使用网络模拟工具为用户播放器端到视频服务器端之间的网络传输增加20%的丢包,此时基于TCP传输协议的播放器会出现明显卡顿而基于QUIC传输协议的播放器则仍可保持较为流畅的播放状态,二者会出现5~10s的播放时间差,不难发现QUIC在弱网环境下的传输性能优势非常明显。

其次我们模拟增加每个数据包的延迟如增加到200ms,随后使两个播放器从同一帧开始播放,不难观察到基于TCP协议播放器的画面明显滞后,QUIC的首帧展示也更快。

2. QUIC协议特性

无论是弱网环境的卡顿还是首帧展示,QUIC相对于TCP的实际传输性能提升都十分明显。这与QUIC协议本身的一些特性紧密相关,主要包含以下四部分:

2.1 极短的建连时间

在QUIC的建连时间中大部分为0-ORTT,极少部分是1-RTT,如何实现这样的分配?首先大家知道,TCP的一个建连包含三次握手,而如果基于HTTPS加密则还需包含TLS一层的一个握手,同时增加1 RTT的时间;综合来看,已完成建连的TCP连接进行握手大概需要2 RTT,而首次建连的TCP则需3 RTT,其中便包括TLS的证书交换。但对于QUIC协议,若客户端之前未建连,其第一次建连时需在客户端直接生成证书与和协议栈相关的配置且附带一个ID,这些数据会与请求数据一起直接发送并保存在服务端,假若服务端已存在以上数据那么系统会直接进行校验操作并直接回复数据;而已建连的客户端则仅需0-RTTs时间,初次建连的QUIC服务端为便于进行建连与校验会把ID保存在服务端本地,待服务端完成校验即可发送证书至客户端并进行客户端校验,校验成功即可直接启动数字交换;且对于第一次建连的QUIC而言只需1 RTT就可完成建连并允许后续的数据交互,以上就是QUIC的建连时间特性——大部分0-RTT、极少部分1-RTT。

2.2 多路复用

QUIC协议的第二条特性为完全多路复用,以HTTP1.1为例,每条数据流基于一个TCP连接,每个TCP连接都单独传输数据,但此TCP连接方案会明显增加服务端与客户端的并发负载;HTTP/2对此问题进行了有效优化也就是采用多路复用的传输策略,通过一条TCP连接传输多路数据,但此方案容易造成队首阻塞问题:以上图展示的HTTP/2数据流为例,若Stream 2丢失那么Stream 1与Stream 3都会被阻塞,直到丢失的Stream 2数据重传完成之后Stream 1与Stream 3才能被继续传输,这种因为一条数据流的丢失重传等问题造成其他多条数据流阻塞的现象被称为队首阻塞问题;QUIC对此问题进行了修正,也就是把每个重传过程安排在每条Stream中单独完成,由于Stream本质上是一个基于UDP的小数据包,所以这种方案并不会造成队首阻塞问题。

2.3 灵活的拥塞控制

QUIC的第三个特性被称为灵活的拥塞控制,QUIC能够在操作系统层面实现完全用户态得益于协议栈非常灵活的拥塞控制。如我们之前熟知的被用于TCP的BBR拥塞控制算法也是一开始在QUIC上实验成功之后才被移植到TCP内核中。当然这种将模块移植进内核的尝试是一个非常漫长的过程,但为了实现较为良好的拥塞控制并达到用户态要求,此方案不失为一种良策。

2.4 连接转移

QUIC的最后一个特性被称为连接转移。什么是连接转移?假设当你正在家中使用WLAN观看视频时需要外出办事,当你走出家门时手机也会从通过WLAN下载数据改为通过蜂窝网络下载,在WLAN与蜂窝网络切换的瞬间TCP连接会被切断再重连,这是因为TCP采用包括原IP、目标IP、原端口、目标端口在内的四元组方式表征一个连接;QUIC并未采用四元组的表征方式,而是将数据包中一个64位的数值ID作为表征,无论WLAN与蜂窝网络如何切换,只要发送至的服务端数据当中的ConnectionID一致,服务端就会默认其为同一个连接,从而避免出现切断重连的过程。

3. 视频云的QUIC实践

3.1 Roadmap

接下来我将重点介绍B站开发QUIC协议的实践经验。我们在开发QUIC协议之前,遇到了以下两个难点:首先,作为一个正在开发中的协议草案,QUIC协议标准本身需要频繁进行迭代更新,大约1.5个月更新一个版本。如现在被广泛使用的QUIC43就是不到一年前从QUIC37、35或39等版本迭代而来,而不断跟进此协议标准的迭代升级确实是一件很难的事情;其次是开发QUIC网络协议本身是一个比较底层的实践,需要开发者具备较强的技术素养才能攻克其中诸多的技术难点。B站已在服务端全面上线QUIC,客户端的QUIC也正在灰度上线中。

3.2 技术选型

我们尝试探索多元化技术选型,通过一个季度的调研确定了以下几个可实现QUIC的常见开源项目:Libquic、Caddy&Quic-Go、Stellite&Isquic与Chromium。我们尝试借助这几个开源项目快速搭建并上线QUIC服务端,并仔细对比这几个方案的利弊:Libquic虽然具有一些可在Chromium中实现的优势,但其早在两年前就已经停止更新;Caddy&Quic-Go作为使用(……long)实现的单协议栈,其测试性能无法满足我们的上线标准;Stellite&Isquic作为商业解决方案不但需要我们花大量成本进行部署,而且其协议栈的功能也不够全面;Chromium作为Google官方的开源项目,虽然与QUIC协议标准始终保持一致的版本更新,但其接近两千多万行的庞大代码量明显增加了我们的运维压力。基于以上调研结果,最终我们决定使用Chromium快速搭建QUIC服务端,主要分为以下两步:首先使用Chromium的QUIC协议栈模块打包一些API,其次是自主实现能够满足生产环境的UDP Server,结合以上两者完成QUIC服务端的上线开发。

软件:一半错误、potplayer成人直播tvpot中性能,吗时候再成中在穿着都是2 天前赢使用

上图展示的就是我们在调研与探索过程中参考的资料来源。

3.3 初期架构

上图展示了B站在QUIC服务端实现的一个初期架构,为了与B站目前点直播系统的(NGX)体系兼容,我们仅将QUIC服务端作为一个代理接收来自公网的数据并转发至本机的(NGX )服务器。由上图架构不难发现我们的工作重点是根据在主线程上进行收发的UDP数据包中的一些连接,将ConnectID分发至不同的工作线程。每个工作线程上都会运行一个QUIC协议栈,从而进一步发掘整个QUIC服务器的性能。需要注意的是,非单一的QUIC协议栈在处理网络UDP数据包或QUIC数据包时存在限制条件,也就是必须按照其ConnectID进行分发,否则就会出现一个连接进入两个协议栈的错误,继而导致数据丢失甚至服务宕机的状况。在此限制条件下此架构可实现如负载均衡等功能。与此同时我们通过QUIC到TCP的代理转发,把QUIC的HTTP2的协议转发为(NGX) Server使其能够为本地的(NGX) Server服务并接收(NGX) Server的回复,最终将(回复)转化为UDP包返回至QUIC客户端,这便是我们QUIC服务端的初期架构与细节。

3.4 使用方式

用户可直接使用内核支持QUIC的Web端如Chrome、QQ浏览器、Opera(内核)观看B站的视频;与此同时我们也会尽快灰度上线移动端的QUIC灰,为大家带来酣畅淋漓的QUIC高效传输体验。

4. QUIC展望

展望未来的QUIC,机遇和挑战并存。作为较早入局QUIC探索的开发团队,我们除了期待更优秀的适合视频传输的拥塞控制模型算法早日出现,也期待有更多建立在QUIC之上的协议如RTMP等的出现;当然,我们也面临着诸多挑战,如一旦gQUIC、iQUIC或HTTP/3成为标准,那么我们的协议栈就会面临大范围的改动,同时迭代更新也会增加我们的开发成本;其次,由于不存在流量控制,容易被用于流量攻击,UDP包存在被运营商特殊对待的可能;最后是移动端的不同平台(如Android、iOS)对QUIC的态度与支持力度,我们的愿景是与全行业志同道合者一起致力于QUIC的标准化,彼此分享研究技术亮点,共同努力使用户的音视频流媒体观看体验登上一个新的高度。

精品文章推荐

技术干货: