基于 http-flv 的抖音直播端到端延迟优化实践

316次阅读  |  发布于2年以前

延迟是怎么产生的?

传统直播方案(http-flv、RTMP 等)的架构以及延迟量级如下图所示:

以抖音直播为例,直播链路各环节延迟贡献如下:

从各环节延迟贡献看,容易得出一个直观的结论:端到端延迟过大主要是播放器的防抖 buffer 造成,这个表面现象也经常会导致很多同学,认为降低播放器的 buffer,就能降低延迟。这个说法的对错,取决于从什么角度解释。在辩证这个结论前,我们先详细拆解介绍下直播全链路的延迟:

上图主要更细致地拆解了流媒体服务环节,即 CDN 传输链路,拆解为上行(收流节点和上层节点)、源站、下行(上层节点和拉流边缘节点)。各环节延迟归因如下:

主播端(推流器)

主要包含编码延迟以及发送缓存引入的延迟(多数主播网络情况良好,发送缓存延迟平均只有 20 ~ 30ms),这个环节的延迟可优化空间不多,虽然通过调节编码器参数可有效降低编码延迟,但带来的是画质的损失,同时也影响压缩效果,因此多数集中在优化弱网传输(不过出发点是为了提供用户观看流畅体验,而不在于降低延迟)

收流边缘节点&中间链路

针对 http-flv 不需要分片的协议,CDN 传输各节点都是在收到流数据就直接转发到下一个节点,这个环节主要的延迟是由链路传输引起的,与链路长度正相关,一般平均不超过 200ms。

如果播放端拉转码流,那么在网络传输延迟基础之上,会额外增加转码延迟(目前各大 CDN 厂商编码延迟大概分布在 300ms ~ 2s),包括解码延迟和转码延迟,其中对于无 B 帧的场景,解码延迟较小,主要是编码延迟。编码延迟主要是受编码器缓存帧数影响,假设 FPS=15,那么缓存 6 帧,延迟就 400ms,该部分延迟与推流编码延迟一样,同样可以通过调整转码参数来降低转码延迟,但也同样会带来画质与压缩率的损失,因此这部分延迟需要根据实际场景综合来考虑,如果对延迟要求很高,可以调整下。

拉流边缘节点

不考虑回源的情况,这个环节主要影响延迟的是 gop cache 策略(有的 CDN 厂商也叫做快启 buffer 策略或者快启 cache),即在边缘节点缓存一路流最新的几个 gop(一般媒体时长平均为 5 ~ 7s),目的是为了在拉流请求建立时,可以有媒体数据即时发送,优化首帧和卡顿,这样也就导致了播放端收到的第一帧数据就是 5 ~ 7s 前的旧数据,第一帧的延迟就达到了 5 ~ 7s(这个环节才是端到端延迟过大的根因)。

CDN gopCache 的逻辑

字节与 CDN 厂商沟通约定 gop cache 按照下限优先来下发数据,比如下限 6s,表示先在缓存数据中定位最新 6s 的数据,然后向 6s 前的旧数据查找第一个关键帧下发,保证下发第一帧距离最新帧之间的时长不低于 6s:

如上图,如果不考虑生产端和中间链路的延迟,那么 buffer 长度 7.2s 可以近似看作播放的初始端到端延迟,在播放器正常播放且无卡顿的前提下,这个延迟会一直持续到退出直播间,不会变化。这里介绍几个初始延迟计算的通用公式:

例如抖音秀场 gop 大小是固定的 2s,假设 gopCache 下限为 6s,那么观众的合理端到端延迟分布区间为:[6, 8]s,根据用户请求的时间点,所有观众的延迟都会均匀分布在这个区间内,因此不同观众间的延迟 diff 最大不超过一个 gop 的长度 2s(这点是优化设备间延迟差的理论基础)

观众(播放器)

播放器在 io 模块有分配缓存 buffer(抖音线上分配 buffer 最大为 20s,也就是最多可容纳 20s 的媒体数据,这个 buffer 其实越大越好,抗网络抖动能力也越强),用于存放从 CDN 边缘节点下载到的流媒体数据。播放器下载是主动下载,在可分配的 buffer 队列未充满的前提下,io 线程是连续下载流媒体数据并存放到 buffer 中,直到没有空闲 buffer 可利用为止。因此,观众网络状况良好的情况下,在用户请求播放,建立链接后,CDN 的边缘节点的快启 buffer,会很快都被下载到播放器的 buffer 中,后续渲染环节消费速度远低于 i/o 下载的速度,这样端到端的延迟就主要分布到了播放器的 buffer 中。但只说明启播后,直播链路的延迟从 CDN 的 gopCache,转移到了播放器,播放器 buffer 并不是延迟的根因,因此,降低播放器的最大缓存 buffer,并不能降低延迟。如果换个角度理解,降低播放器 buffer 中实际缓存的数据,会降低延迟这个说法是正确的,比如通过倍速播放或者丢帧。

现在了解了全链路延迟是怎么产生的,我们可以确认以下几点:

为什么要优化延迟?

传统的直播技术延迟非常大,从观众评论到看到主播给出反馈一般要在 5-10 秒以上。几个典型的尴尬场景:

在线教育,学生提问,老师都讲到下一个知识点了,再返回来回答。

电商直播,询问宝贝信息,主播“视而不理”。

打赏后迟迟听不到主播的口播感谢。

假设端到端延迟为 6s,那么在线教育和电商直播两个场景,互动延迟由面对面的 0s,增加到了 12s,如下图所示:

打赏场景,互动延迟由面对面的 0s,增加到了 6s,如下图所示:

在别人的呐喊声知道球进了,你看的还是直播吗?

这个场景的延迟体验问题,并不是某次拉流请求端到端高延迟导致的,主要是因为不同用户间的延迟不一致导致,如下图:

可见,高延时影响了直播互动体验,阻碍了直播在一些场景的落地,特别在电商直播,直播间的评论提问是观众和主播互动的一个重要手段,主播的实时互动反馈对直播间的活跃度和交易达成至关重要。

以上两类由于延迟导致体验差的场景,分别对应我们 QoS 指标中的平均端到端延迟、延迟设备差两个指标,延迟相关的优化也会以这两个指标为标准。

延迟体验优化实践案例

百万英雄答题

直播流链路

延迟需求

需求分析

解决方案

gop=2s,gopCache 下限为 5s,那么首帧延迟分布在[5s, 5+2s]内,平均延迟为(5+(5+2))/2=6s,具体措施如下:

  1. 各家 CDN 快启策略需要设置为下限优先,并且快启 buffer 阈值为 5s
  2. 推流参数设置需要设置 gop=2s,且保持稳定:保证观看同一路流的用户,时延 diff 在 2s 内
  3. 转码配置需要保持 gop=2s 的配置,并且 I 帧对齐:保证观看不同转码流的用户,时延 diff 在 2s 内

调整 gop=2s 后,仅能保证一直流畅播放无卡顿的 vv,彼此直接的延迟 diff 在 2s 以内,但对于观播过程中发生卡顿的用户,累计延迟增加的情况,延迟 diff 会越来越大,例如用户 A 卡 4s 后,恢复正常播放,那么 A 的端到端延迟会增加 4s,如果 A,B,C 是一个组队答题的小伙伴,A 的题目解说会一直落后 B 和 C,这样的体验很不好。因此需要针对这类场景的设备延迟差做优化:这时候需要播放器追帧微调,使 A 的播放速度追上 B 和 C。具体措施如下:

  1. 追帧的原则是:在 A 的播放器 buffer 超过 6s 时,就开始倍速播放,直到 buffer 低于 6s,这时候 A 就追上了 B 和 C
  2. 追帧阈值 6s,追帧速度是 1.4,这样设置的效果时,A 观众在延迟落后 4s 的情况下,追帧 10s 即可赶上 B 和 C,实际阈值的设置,可以根据需求来确定,原则上是在延迟满足需求时,尽量不触发追帧,保持正常速度播放

效果验收

相对于第一届百万英雄答题,延迟不同步的用户反馈大量减少

4s 低延迟字节内购会

直播流链路

类似于百万英雄

延迟需求

需求分析

解决方案

配置项 value 配置方式
推流 gop 2s OBS 推流器配置
转码 gop 2s 转码模版

相对于百万英雄答题场景,内购会对互动延迟敏感,因此这里相对于百万英雄答题需要做特殊配置,由于各家厂商默认 gopCache 策略,平均端到端延迟在 6s 左右,不满足需求的 4s,需要通过配置 url query 参数控制厂商的 gopCache 策略,保证延迟在 4s 左右

  1. 延迟等级:4s
  2. 参数配置目标:降低不同设备间延迟差,控制用户延迟分布在[3000ms, 4000ms]内,这样保证设备间延迟差最大不超过 1s——延迟低的用户慢放,延迟高的用户追帧,从而更精确的控制设备延迟差低于 gop 长度 2s

内购会上链接或者答题,是根据现场助理观播的延迟来确定上链接或者发题的倒计时时机,由于有快慢放对齐设备延迟差的过程,建议助理看播 1min 后,延迟稳定后,再确定倒计时

效果验收

抖音直播-FLV 低延迟-3s

直播流链路

需求目标

需求分析

解决方案

本次需求场景的受众是抖音的所有直播用户,网络质量的优劣也是参差不齐的,在保证满足降低延迟的需求目标,我们还需要保证观播的流畅性不要负向太多。

延迟解决方案

  1. gop 下调为 2s
  2. 配置 gopCache 下限参数为 1800ms,延迟区间为[1800+200ms,3800+200ms],平均 3s

卡顿优化方案

1 . 先验知识科普

2 . 基于网络质量的个性化启播 buffer 策略

3 . 基于网络质量的个性化延迟策略

基于数据统计发现:网络分级 1 ~ 4 的 vv 占比为 5.54%,但卡顿指标却贡献了 47.83%,再结合本需求场景设备间延迟差并不是核心指标,因此可通过个性化延迟来优化卡顿。

4 . 客户端管控 CDN 卡顿优化策略

在需求推进过程中发现两个奇怪的现象:

结合以上两个现象,基本可以判断低延迟情况下,CDN 在启播阶段更容易丢帧,且启播丢帧会严重影响 QoE 体验,因此管控 CDN 丢帧策略,对 QoS(视频渲染卡顿)以及 QoE 都是有正向优化效果的,管控规则如下:

参数名 描述 规则
protected_period 拉流 session 丢帧保护期:请求开始的前 n 毫秒不能丢帧 protected_period=0:表示整个拉流过程中都不能丢帧;当 value>0 时,比如 protected_period=5000:表示拉流 session 的前 5000ms 不能丢帧,5000ms 是以系统时钟(本地时间)纬度来衡量
gop_keep_duration 发生丢帧的 gop 保留时长下限:时长是视频流纬度的 duration 当 value>0 时,比如 gop_keep_duration =2000ms,表示丢帧后,对应 gop 必须保留发送到用户的的视频流总时长不低于 2000ms

最终效果验收

由于低延迟降低了 gopCache,延迟下降到 3s,相对于 7s 高延迟 FLV,在启播时会少下载 4s 的数据,尤其抖音直播预览流占比达到 70%,因此低延迟 FLV 可以节省不必要的带宽成本,成本收益为 10%

关于延迟的思考

思考一:观众对互动延迟的感知是否存在拐点,延迟降到一定程度,用户感知不到?我们从三个典型的互动场景来思考:

思考二:在传统标准直播 http-flv 场景下,是否可以依然基于本文中介绍的方法,继续下探更低延迟,比如 1s?个人判断是可以做到的,但面临的挑战也更多,需要更精细的播控策略来平衡延迟与播放流畅性,比如:

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8