QUIC在京东直播的应用与实践 | 京东云技术团队

京东云开发者
• 阅读 781

作者:京东零售 周凯

一. 前言与背景

国内的互联网直播技术从2005年前后兴起,彼时最具代表性的直播产品是由PPLive创始人姚欣在华中科技大学就读期间发起的校园直播项目PPLive。当时的直播技术用的还是基于windows系统自带的mediaplayer内置的COM组件开发的播放器,采用的是RTSP协议。受当时的互联网传输带宽及成本限制,PPLive并没有采用现在比较流行的单播技术,而是采用P2P技术分发直播流。国内的直播技术也进入了一段以P2P技术为主的时期,其中比较有代表性的就是PPLive和PPStream。用P2P技术分发直播流,具有运营成本低的明显优势,每一个参与播放的终端都是一个潜在的数据热点,网络质量随着观看直播流的客户端的增加而增加。但P2P技术也有自身的不足,缺乏观众的冷门资源因参与数据共享的客户端稀少而难以保证播放质量,另外P2P难以保证UDP打洞穿透率、需要下载专用的播放器等都是限制用户数量增长的因素。

P2P直播分发技术注定是一个过渡性的技术。2005年以后,由于早期的HTML标准尚不完善,各大浏览器存在实现上的差异,被寄予厚望的HTML5规范也还尚未定稿,基于HTML的视频播放技术也不成熟。彼时,Adobe公司从Macromedia公司收购的网页多媒体插件flashplayer在这种情况下脱颖而出。在开发层面,flashplayer因其优异的多媒体表现力以及完善的开发语言和调试工具,降低了网页播放器的开发门槛。在音视频质量方面,Flashplayer内置的On2公司的VP6视频编解码器无论是在编码质量还是在解码效率上在当时都非常优秀,随着2003年才定稿的H.264/AVC视频编解码器及更高质量的AAC音频解码器也很快被内置到flashplayer内核,进一步提高了flashplayer的音视频能力。在播放器推广层面,基于flashplayer开发的播放器文件,能像分发网页一样通过网站服务器下发和更新,这极大地降低了视频网站的推广难度。上述原因,促使flashplayer成为当时最好的网页视频播放器内核。在flashplayer的技术加持下,视频点播网站如雨后春笋般涌现,尤其在2006年google收购youtube后,网页视频点播网站迎来了爆发,六间房、优酷、土豆等视频网站先后融入巨资,从众多点播网站中脱颖而出。彼时,flashplayer作为绝大部分视频点播网站统一使用的网页播放器,装机率快速提高,逐步成为事实上的网页多媒体播放器标准。2009年,随着Adobe将flashplayer内置的革命性的流媒体传输协议RTMP(Real-Time Messaging Protocol)规范开放,本就已经方兴未艾的RTMP直播技术,进入了发展的快车道。各种基于RTMP协议的开源实现陆续出现,涵盖服务器和播放器。由此,互联网直播进入了由flashplayer和RTMP协议主导的时代。

RTMP是flashplayer原生支持的流媒体传输协议,支持点播和直播模式,经过十多年的大规模应用,已经成为当前国内应用最为广泛的直播协议,各大CDN厂商都已经支持。国内技术圈还发展出了HTTP-FLV协议,即将RTMP中的直播音视频流封装成FLV文件流,通过HTTP协议传输,这进一步降低了直播技术的接入成本和实现难度。

RTMP和HTTP-FLV都是基于TCP的直播协议,TCP固有的基于拥塞控制的传输策略在需要稳定、大量传输数据的直播场景下显得过于保守,偶发的丢包或网络抖动都会造成数据收发速率的急剧下降,从而造成画面及声音的卡顿,影响直播的质量及体验。而基于带宽和延时预测的QUIC传输协议的出现,为直播行业提供了一个提升直播质量和用户体验的新的选项。

二. QUIC介绍

QUIC(读作“quick”)是一个通用的传输层网络协议,最初由Google的Jim Roskind设计。该协议于2012年实现并部署,2013年随着实验范围的扩大而公开发布,并向IETF描述。虽然长期处于互联网草案(英语:Internet Draft)阶段,但从Chrome浏览器至Google服务器的连接中超过一半的连接都使用了QUIC。Microsoft Edge、Firefox都已支持此协议;Safari实现了QUIC,但默认情况下没有启用。QUIC于RFC9000中被正式标准化。

虽然QUIC的名称最初是“快速UDP互联网连接”(Quick UDP Internet Connection)的首字母缩写,但IETF指定的标准中QUIC并不是任何内容的缩写。QUIC提高了目前使用TCP的面向连接的网络应用的性能。它通过使用用户数据报协议(UDP)在两个端点之间建立若干个多路连接来实现这一目标,其目的是为了在网络层淘汰TCP,以满足许多应用的需求,因此该协议偶尔也会获得 “TCP/2”的昵称。

QUIC与HTTP/2的多路复用连接协同工作,允许多个数据流独立到达所有端点,因此不受涉及其他数据流的丢包影响。相反,HTTP/2建立在传输控制协议(TCP)上,如果任何一个TCP数据包延迟或丢失,所有多路数据流都会遭受队头阻塞延迟。

QUIC的次要目标包括降低连接和传输时延,以及每个方向的带宽估计以避免拥塞。它还将拥塞控制算法移到了两个端点的使用者空间,而不是内核空间,据称这将使这些算法得到更快的改进。此外,该协议还可以扩展前向纠错(FEC),以进一步提高预期错误时的性能,这被视为协议演进的下一步。

三. 京东直播技术简介

京东直播体系从零开始构建,如下图所示,涵盖四大业务模块:推流端、中台源站、直播云CDN及播放端。

QUIC在京东直播的应用与实践 | 京东云技术团队

图1.京东直播产品体系

从上图可以看出,直播流的端到端传输,中间要经过多个链路。直播数据因数据量大、占用带宽高、传输距离长而符合典型的Long-Fat(长肥)网络定义。在应用QUIC技术之前,京东的直播产品都是使用基于TCP的协议(RTMP/HTTP-FLV/HLS等)进行直播流数据传输,TCP因其保守的拥堵控制策略,在应对Long-Fat网络应用场景时差强人意,QUIC技术的出现,为优化直播传输质量提供了新的选择。

京东从2021年上半年开始研究QUIC,基于QUIC ietf v1版本开发了自研的QUIC实现QUIC-Pro,并最先在京东的直播场景落地。QUIC在京东直播技术体系的落地过程并非一蹴而就,而是循序渐进的。考虑到直播数据流从CDN边缘服务器分发到用户端是最复杂的“最后一公里”问题,因此,我们选择QUIC最初的落地场景是直播的分发和播放。

QUIC落地之前,为了量化直播质量,方便对比优化收益,我们制定了统一的全链路质量监控及数据上报标准,收集推流端、直播源站、直播云CDN及播放端等所有环节的跟传输、播放相关的监控数据,并统一上报到数据收集平台进行聚合、分类及统计,在众多质量指标中,选定画面首开时长、卡顿率及播放失败率作为播放质量的重要量化参考指标。

本文将分别从推流端、中台源站、直播云CDN及播放端四个部分串烧式地介绍与直播相关的一些技术实践,并重点介绍QUIC技术的应用情况及收益。

四. 推流端技术

京东直播支持的推流端包括京东视频APP,PC桌面端推流工具以及web网页端企业直播工具。京东视频APP及PC桌面端推流工具除支持真人直播及美颜功能外,还支持数字人直播,数字人直播数据流程如下图所示。

QUIC在京东直播的应用与实践 | 京东云技术团队

图2.京东数字人直播SDK架构

上图中,VideoSource和AudioRecord分别控制图像和声音数据的输出,当真人直播时,VideoSource打开CameraCapturer,采集摄像头图像数据,并送到Filter滤镜链条进行美颜等操作,然后进行视频编码并打包发送,音频则通过AudioRecord打开MicrophoneRecord,采集麦克风声音进行录制、编码并打包发送。

当采用数字人直播时,流程经过图中黄色模块,TextureFactory模拟摄像头运行机制,按帧率设置定期生成空白纹理,纹理经过VideoSource进入滤镜链条,滤镜链条中有一个3DEngineFilter滤镜,将京东自研的数字人3D引擎生成的数字人图像渲染到纹理,然后在屏幕上展示该纹理,同时将纹理上的图像进行编码、打包、发送。数字人的音频,则通过AudioPlayer控制音频播放到设备的同时,将音频采样数据输出到AudioRecord,然后经过编码、打包,并发送出去。

五. 直播源站与CDN分发网络

京东直播包括实时音视频源站、实时转码、录制、审核等业务,推流端的实时音视频流都是先推到中台源站,然后再经过处理通过京东直播云CDN分发到播放端。中台源站还负责直播连麦相关业务的处理,包括混音、合屏等操作。

QUIC在京东直播的应用与实践 | 京东云技术团队

图3.京东中台直播源站低延迟直播服务架构

直播云CDN通过京东云对外提供赋能,直播云CDN承载了京东主站、京喜等含直播功能的产品的日常直播流分发服务。经过近一年的密切合作,京东直播中台团队和京东直播云CDN团队已将共建的QUIC直播流分发服务全量部署到所有服务节点。直播云服务流程如下图所示。

QUIC在京东直播的应用与实践 | 京东云技术团队

图4.京东直播云CDN分发流程图

上图是京东直播云CDN对直播流的分发流程图,最左侧是直播源站或直播应用直推直播流到边缘推流集群,经过录制、转码截图、中转集群等中间模块及服务处理,最后转推给第三方CDN或经由边缘播放集群分发给播放端。

六. QUIC服务端设计

当前网络上开源的服务端QUIC协议栈实现方案有多种,例如Chromium QUIC、Lsquic、Nginx 官方quic、cloudfare quic等。其中Chromium QUIC发展的最早,也相对最成熟。因此JDQUIC服务端依托Chromium QUIC,使用了其QUIC协议栈相关源码,服务器框架及其他所有代码则为自研。

6.1.JDQUIC服务器模式

为尽量减少对现有直播CDN分发体系的改造,并保持QUIC的可扩展性及高效迭代更新,JDQUIC服务器采用反向代理模式进行QUIC直播流的请求、转换与分发。

QUIC在京东直播的应用与实践 | 京东云技术团队

图5.JDQuicServer工作流程

如上图显示,手机端播放器发送QUIC直播流拉流请求到JDQuic-Server服务器,JDQuic-Server服务器将请求格式转换为普通的http或tcp数据,发送给后端Web或者TCP服务器,然后接收后端HTTP-FLV服务器返回的直播流数据并通过HTTP/QUIC协议下发给播放器。整个服务过程无需对后端服务体系作任何修改。

由于JDQUIC服务器一般和后端服务器部署在同一机房、甚至同一机器上,两者之间的数据传输延迟基本可以忽略不计。

6.2. JDQUIC服务端架构

JDQUIC服务端采用多进程单线程架构。消息驱动采用了Libevent epoll模式,QUIC协议栈则使用了Chromium QUIC协议栈相关代码。如下所示:

QUIC在京东直播的应用与实践 | 京东云技术团队

图6.JDQuic-Servrer内部架构

JDQUIC 服务端采用单线程多进程架构,单机多进程采用内核ebpf进行负载均衡。

单线程内部采用Libevent epoll进行消息监听和分发,TCP UDP Unix domain、http等多种协议依托Libevnet进行收发,同时超时和异步消息也通过Libevent架构进行回调。

Libevent 收上来的UDP数据包,在Chromium QUIC协议栈进行解析,还原出原始Http或者裸数据。这些数据经过线程内无锁调度模块,传给后端Nghttp2或tcp udp client模块,发送给后端服务器。

6.3. JDQUIC连接迁移

网络的切换在当今移动网络大规模普及的背景下,是经常发生的事情。考虑如下场景,当用户正在户外用移动4G/5G网络看着直播的过程中,走到了一个具备WIFI网络的地方,连上了可用的wifi网络,此时,网络切换便发生了。如果要保证直播连接在网络切换后仍然保持畅通,需要实现一套连接迁移机制。JDQUIC-server的实现及工作原理,如图7所示:

QUIC在京东直播的应用与实践 | 京东云技术团队

图7.JDQuic-Server连接迁移原理

【工作流程】

  1. 手机端从4G网络切到wifi网络。

  2. 手机端网络连到不同的运营商机房(从移动机房切到联通机房)。

  3. Ospf和nftable负载分配到一个机器quic server实例。

  4. Quic server 通过quic数据包中的connection id中第一个字节,判断数据包该发回哪个机房。

  5. Quic server 把数据包转发给原来的机房。

  6. 原来的机房再负载到正确的quic实例。

【说明】

• Ospf负载: 三层负载均衡服务,硬件负载,效率很高。

• Nftable单机负载: 操作系统内核级别的负载服务。

• QUIC服务: quic服务器,可以将quic协议转换为http去后端FMS/SRS拉流。

• 后端FMS/SRS:直播流媒体/CDN服务器。

• 红色箭头:手机端首次播放直播的拉流路线。

• 蓝色箭头:手机端网络切换WIFI后进行连接迁移的拉流路线。

6.4. JDQUIC DCID设计

连接迁移时,联通机房的quic server想要找到回源的机器,需要从quic数据包的DestionationConntion id字段获取机房信息,如下图所示。

QUIC在京东直播的应用与实践 | 京东云技术团队

图8.JDQuic-Server CID扩展设计方案

CID字段取一个字节来映射机房信息,例如0x01表示长春移动,0x02表示长春联通等。

6.5. JDQUIC ebpf设计

6.5.1. eBPF简介

Linux 内核一直是实现监控/可观测性、网络和安全功能的理想地方。 不过很多情况下这并非易事,因为这些工作需要修改内核源码或加载内核模块, 最终实现形式是在已有的层层抽象之上叠加新的抽象。 eBPF 是一项革命性技术,它能在内核中运行沙箱程序(sandbox programs), 而无需修改内核源码或者加载内核模块。

将 Linux 内核变成可编程之后,就能基于现有的(而非增加新的)抽象层来打造更加智能、 功能更加丰富的基础设施软件,而不会增加系统的复杂度,也不会牺牲执行效率和安全性。

QUIC在京东直播的应用与实践 | 京东云技术团队

图9.eBPF原理及工作流程

6.5.2. eBPF在JDQuic-Server中的应用

linux内核中,通过ebpf维护两个映射表,并编写一段ebpf JIT(即时编译)程序。客户端QUIC数据包进来后,ebpf JIT程序根据ip端口、CID进行hash,分别访问两个map表,来判断需要转发给哪个后端QUIC实例。其中,ip和端口为UDP协议数据包的字段,包括源IP、目的IP、源端口、目的端口(合称四元组),如图所示。

QUIC在京东直播的应用与实践 | 京东云技术团队

图10.JDQuic-Server内部ebpf负载均衡原理

七. QUIC技术收益

QUIC协议基于带宽瓶颈预测及环路延时预测的传输控制算法,相比TCP的基于网络拥塞的控制算法,在抗网络抖动、提高网络传输速率方面有显著优势。根据QuicPro在线上Android应用内的直播场景中的使用情况统计数据显示,直播卡顿率较TCP由1.43%降为1.14%,降幅为20%,首开时间较TCP的949毫秒降为659毫秒,降幅为30.5%,如下图所示:

QUIC在京东直播的应用与实践 | 京东云技术团队

图11.TCP与QUIC分别在直播卡顿率及首开时间上的对比

八. 结语

京东直播经过4年多的发展,技术上无论是服务架构还是播放协议都经过了多轮迭代,截至本文成文,仍在进行迄今为止最大规模的改造升级,涉及全链路的协议升级与架构优化。协议上,将原有的基于TCP的信令、推流、分发、播放等环节升级为QUIC协议,在服务架构上,进行推流及媒体服务边缘化改造,在分发上,中台与京东云直播CDN兄弟部门共建低延迟分发网络,我们共同的目标是提升传输质量、降低卡顿率的同时,将直播端到端的延迟降低到2秒甚至是1秒以内。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
PPDB:今晚老齐直播
【今晚老齐直播】今晚(本周三晚)20:0021:00小白开始“用”飞桨(https://www.oschina.net/action/visit/ad?id1185)由PPDE(飞桨(https://www.oschina.net/action/visit/ad?id1185)开发者专家计划)成员老齐,为深度学习小白指点迷津。
Wesley13 Wesley13
3年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
3年前
JavaScript常用函数
1\.字符串长度截取functioncutstr(str,len){vartemp,icount0,patrn/^\x00\xff/,strre"";for(vari
Stella981 Stella981
3年前
Jenkins 插件开发之旅:两天内从 idea 到发布(上篇)
本文首发于:Jenkins中文社区(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fjenkinszh.cn)!huashan(https://oscimg.oschina.net/oscnet/f499d5b4f76f20cf0bce2a00af236d10265.jpg)
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_