乐趣区

关于直播:最后一公里从直播拉流读懂直播链路

前言

直播是一个宏大而简单的业务状态,一个优良的直播零碎波及泛滥团队的独特合作,有十分残缺的直播链路。

那么,直播链路中都有哪些角色?这些角色要解决的是哪些问题?要优化某个环节时须要哪些角色的配合?这些角色优化链路的伎俩有哪些?……

想要厘清这些问题,对直播全链路接触比拟少的同学无疑要花费大量的工夫能力实现。本文将从直播拉流切入,力求帮忙有趣味的同学简单明了而全面地了解整个直播链路。

为什么直播拉流是“最初一公里”

从整个直播链路来看,直播拉流作为直播内容触达观众的最初一个环节,从客观现实上来说,就是直播链路的“最初一公里”。

直播拉流作为整个直播链路的“最初一公里”,链路上任何一个前置环节呈现问题,都会在拉流过程中体现进去。通过剖析、了解拉流过程中产生的各类问题,会是了解直播链路最无效的形式之一。

作为直播内容生产的关键环节,如何优化这“最初一公里”上的各类体验,是每个直播从业人员一直摸索的问题,从直播拉流了解怎么做好直播无疑是一个好的抉择。

从直播业务了解直播链路

上图所示是从业务层面看到的一次直播观播过程,也是对直播拉流的一个高度简化。麻雀虽小,但五脏俱全,图中显式或隐式地涵盖了整个直播链路简直所有要害角色和流程。

直播链路上的要害角色

客户端

客户端中囊括了直播链路中多个 SDK,包含直播中台 SDK、直播推流 SDK,以及直播拉流 SDK。

  • 直播中台 SDK

    • 直播中台 SDK 封装直播间内的所有业务逻辑,可能串联流调度与推拉流 SDK,给推拉流 SDK 提供日志上报、配置下发能力。
  • 直播推流 SDK

    • 直播推流 SDK 作为提供给中台 SDK 的封装层,提供采集、编码、推流、连麦等能力,响应流调度下发的各种配置,例如推流分辨率、码率、编码方式等端上能力,实现推流过程中各类日志信息的采集并上报至中台 SDK。
  • 直播拉流 SDK

    • 直播拉流 SDK 作为提供给中台 SDK 的封装层,提供直播拉流相干能力,同时封装了超分、音量平衡等性能,响应流调度、settings 下发的配置,例如是否开启硬解等端上能力,并实现拉流过程中各类日志信息的采集并上报至中台 SDK。

CDN

CDN 全称是 Content Delivery Network,即内容散发网络。CDN 的外围工作是使内容传输的更快、更稳固。

整个直播零碎中,源站提供了鉴权、转码、回调、禁播等能力。CDN 通过边缘节点,在客户端和源站之间减少一层缓存,申请过的数据会在边缘节点缓存一段时间。

动静申请内容会间接回源拉取,CDN 优化整个传输链路,解决跨网拜访、传输拥塞等问题。

流调度

流调度次要解决与直播流治理相干的工作,外部封装了多家 CDN 供应商,屏蔽了不同 CDN 的细节区别。满足大规模的直播内容散发需要,同时保障了服务的高可用性。提供残缺的解决方案,不便业务方疾速接入直播业务。

要害流程

直播数据流

直播内容从生产到生产次要波及到 推流端 CDN (源站、边缘节点) 以及 拉流端,如图中实箭头所示即为直播数据流方向,其中:

  • 在推流端,推流 SDK 实现了主播的音视频采集,增加美颜、滤镜后,须要通过编码、封装,最终依照指定地址,向 CDN 边缘节点推流;
  • 收流边缘节点在被动收到用户的推流申请后,这个节点会被动地将这个流转推(中继)到下层节点,下层节点通过同样的过程,最终将源流转推到源站;
  • 源站外部会进一步地将源流转推至其余集群实现转码、录制等工作;
  • 在拉流端,拉流 SDK 会依据流地址向 CDN 边缘节点拉流,此时依据这路流在该节点上的缓存命中状况,呈现两种后果:

    • 如果命中缓存,则边缘节点将间接返回缓存数据;
    • 如果未命中缓存,边缘节点将逐级进行回源,最终将流数据返回边缘节点,最终返回播放器。

词语释义:

  • 源流:推流端推出的那路流。
  • 转码:当须要对源流的分辨率、码率、编码等参数进行批改时,就须要进行转码,例如媒体直播往往由业余设施或者三方推流器推出,码率会十分高,间接拉源流会造成带宽压力过大,这时就须要转码。但转码工作自身也须要耗费资源,因而衍生出推流转码、拉流转码等不同转码策略。
  • 回源:往往产生在拉流侧,边缘节点上未命中缓存时,就须要到源站找到所须要的流,该过程即为回源。在上图中示意为虚箭头。实现回源后,边缘节点上会留下这路流的缓存。

流调度

在开播侧,参加到整个流程的角色包含 App、直播 SDK、开播服务、房间服务以及流调度。各角色在开播中的工作如下:

  • 主播在 App 发动开播申请;
  • 开播服务 收到开播申请后依据不同的场景,应用不同的公布点 ID 向 流调度 发动申请创立直播流;
  • 流调度 依据具体要应用的公布点生成对应的推流地址,在这个过程中实现调度,决定应用哪家 CDN 以及应用何种协定等;
  • 开播服务 将推流地址返回至 App 后,App 开始推流、房间服务 在推流胜利后更新流状态;

在看播侧,参加到整个流程的角色包 App、直播 SDK、房间服务以及流调度,其中:

  • 观众在 App 发动进房申请;
  • 房间服务 收到进房申请后,透传申请中携带的用户信息、向 流调度 申请拉流地址;
  • 流调度 收到申请后,依据用户信息进行调度,决定下发的档位信息、性能信息等,并返回至房间服务;
  • 房间服务 获取到流信息后,实现档位映射等逻辑,最终返回 App
  • App 取得流信息后透传至 直播 SDK,并触发播放。

流调度负责了与流治理相干的所有工作,包含流创立、流参数下发、流状态治理、生成推拉流地址等,同时流调度在重保流动中也起着无足轻重的作用。

理解流调度是如何进行调度的,最好的形式是从流调度返回的数据来了解。例如在拉流端,所有调度信息是封装在 stream_data 中,随房间服务接口返回,由中台客户端透传给拉流 SDK,次要蕴含了以下重要信息:

  • 分辨率,除源流外,目前反对的档位有 UHD、HD、SD、LD、MD、AO、AUTO,其中

    • AO、MD 仅在非凡状况下应用,例如后盾播放等不须要高码率的状况
    • 并以不同的标识符别离代表该档位为 H.265 或 H.264 转码
  • 主备,为满足大型流动中的灾备需要,下发流数据中会蕴含两条线路 – 即主(Main)备(Backup)双线,实际上进行了 CDN 调度
  • 格局,在每个档位的每条线路下,个别存在多种格局(format)供拉流应用,例如惯例 FLV、用于超低时延的 RTM、以及时移直播 TSL 等
  • 流调度参数,为直播拉流提供所需的各类参数,例如管制理论应用协定、格局等,在实现调度的同时,防止下层业务感知不必要的细节;此外能够依据具体的场景控制参数的失效范畴,实现从 CDN 维度到单路流维度的精准管制

流调度在直播日常业务中,除了要对线上的默认分辨率、码率等进行管制之外,在重保流动中也起着无足轻重的作用。

  • 当预估带宽很大时,往往须要多家 CDN 来独特分担压力,同时须要依据各家品质来调节占比;
  • 为防止推流端故障往往须要一主一备两路流的热备计划(甚至还须要冷备),拉流端须要在其中一路产生故障时自行切换到另一路;
  • 在带宽压力过大时,须要及时升高下发的默认清晰度以缓解带宽压力,同时在带宽短缺时进步默认清晰度以优化体验。

词语释义

  • ABR:即自适应码率,在直播间中作为 AUTO 分辨率档位,然而 stream_data 中理论不会蕴含这样一个档位,起因在于 ABR 理论是将要应用的若干档位拼装成了一个 MPD(Media Presentation Description)传递给播放器,播放器外部切档时理论应用的是对应档位的流地址。

日志与监控

端监控作为日志上报的终点,将客户端产生的各类日志依照肯定的规定(例如采样率等),进行上报;依据不同的 log_type,上报的日志会被分流并写入到 Kafka 的不同 topic 中;依据数据不同的生产场景及用处,日志会经验一系列解决(例如在 Flink 工作中进行荡涤等),并最终出现到各类数据工具当中。

理解日志数据流对于定位日志相干的各类问题是十分有帮忙的。例如在 Kibana 中找不到日志时,能够从日志是否上报(通过 Charles 抓取端监控 monitor 接口上报数据确认)、分流是否正确(通过查看 log_type 确认,个别不会在该环节呈现问题)、是否因为日志中存在非法字段而被荡涤(通过查看端监控中的原始日志确认)等。

从直播链路了解优化与问题

为什么拉不到流?

直播是一条残缺的链路,链路上任何一个环节中断都会导致拉流端呈现拉流失败的状况:

  • 推流端 - 收流节点中断:单路流所有档位、所有观众将呈现进房时拉不到流或直播间内卡顿;
  • 收流节点 - 源站中断:个别不会呈现,故障源站上的所有流将出现异常;
  • 转码异样:某一个或几个转码档位出现异常,源流失常,观看转码档位的观众报障;
  • 源站 - 拉流节点中断:从故障边缘节点上拉流的全副观众将会异样;
  • 拉流节点 - 拉流端中断:单用户拉流呈现故障。

前述状况次要形容的链路上某个环节中断导致的拉流失败,有时拉流失败其实是首帧耗时过长造成的,这种状况在拉流成功率指标稳定剖析时较为常见:首帧耗时增长导致了拉流成功率降落。

为什么首帧慢?

首帧分阶段剖析

以 HTTP-FLV 为例,从触发播放器的 play 接口到最终实现首帧渲染,须要经验以下这些过程:

  1. DNS 解析: 决定了要从 CDN 的哪个边缘节点拉流。这一过程在拉流 SDK 以及播放器内核中都会产生,后者往往是因为 SDK 层没有解析到 IP 地址。DNS 解析耗时通常在 100ms 左右(localDNS,应用 HTTP-DNS 会进一步减少),因而 HTTP 场景下,咱们能够采纳 IP 直连的形式躲避 DNS 耗时。

    • 实现 IP 直连须要在拉流前获取到 IP 地址,其关键在于 DNS 缓存(缓存之前的 DNS 解析后果,拉流 SDK 层的 DNS 策略)和 DNS 预解析(在 App 启动之后一段时间,对可能用到的所有域名进行 DNS 解析并缓存后果,节点优选 SDK 的外围逻辑);
    • 缓存的 DNS 后果会过期,尤其是 CDN 进行节点笼罩调整时,缓存的 DNS 可能会导致调整不能及时失效,因而须要定期更新 DNS 后果;
    • 用户产生跨网时,因为运营商变动,也会导致此前缓存的 DNS 不可用,因而须要在网络状态发生变化时更新 DNS 后果。

<!—->

  1. TCP 建联: 与边缘节点建设 TCP 连贯,这一过程的耗时次要是三次握手,耗时 1 -RTT。要优化建联耗时,能够通过 TFO(TCP Fast Open,Wiki),或应用 UDP 协定(QUIC、KCP)。
  2. TCP 首包: HTTP 响应实现,此时开始返回音视频数据。如果此时边缘节点上有这路流的缓存,那么将间接返回缓存数据;如果没有命中缓存,TCP 首包返回之前将产生回源。要优化首包耗时,外围思路在于升高回源率,常见伎俩有减少边缘节点缓存放弃工夫,对于大型流动提前进行预热、以保障更多边缘节点上有缓存。
  3. 视频首包: 耗时次要产生在 avformat_find_stream_info 函数调用,播放器在播放前须要探测一定量的流数据,以确定流格局、编码等流信息。因为目前在各个宿主中播放的格局绝对固定,因而不须要探测过多的数据即可确定流信息。所以能够通过调节探测的数据量以优化视频首包耗时。通过减小探测数据量,首包耗时降落 300ms 左右。
    升高流数据探测的数据量也可能会带来不良后果。当探测的数据量过少时,可能会导致读取到的流信息不全,例如只探测到音频数据、没有探测到视频数据(尤其是在音视频数据交错不平均的状况),最终呈现有声无画或声音失常、画面卡住的问题。
默认参数:max_analyze_duration = 5 * AV_TIME_BASE; //5s
fps_probe_size = 20; // 20 帧视频
max_probe_size = 1 << 20; // 1MB
优化参数:
fps_probe_size = 3; // 3 帧视频
  1. 视频首帧解码和视频首帧渲染: 别离实现视频首帧解码和视频首帧渲染,优化的次要方向是 decoder 及 render 实例的预初始化等。

快启 buffer

为了实现秒开,各家 CDN 都在边缘节点上开启了快启 buffer 策略。快启 buffer 的外围逻辑是基于边缘节点上的缓存(GopCache),调节缓存数据下发的具体数据范畴,同时保障视频数据从关键帧开始下发。快启 buffer 也存在不同的策略,例如下限优先或上限优先,后者会要求对接的 CDN 厂商依照上限优先的准则下发缓存数据,比方上限 6s,会先在缓存数据中定位最新 6s 的数据,而后向 6s 前的旧数据查找第一个关键帧下发(解码器要从关键帧开始解码,因而肯定须要从关键帧开始下发)。

词语释义:

  • IP 直连: 行将 HTTP 地址中的 host 局部间接替换为对应的 IP 地址,并在 HTTP 申请的 header 中增加“Host”行,其值为原始的 host,例如http://`x.x.x.x/app/stream .flv "Host: pull-host`.com\r\n"。前述办法最为标准,有的 CDN 也会反对在 host 前直接插入 IP 的形式实现 IP 直连,但该办法并不通用,因而并不倡议应用前插 IP 的办法。

为什么会卡顿?

拉流产生卡顿的间接起因是播放器中的缓存耗尽,此时播放器卡住其实是在进行 Rebuffering。

导致 buffer 耗尽的间接起因是播放器中 buffer 生产的速度高于 buffer 接管的速度:最为常见的例子就是以后拉流端的带宽显著低于视频的码率。同时,在带宽短缺的状况下,链路上前置环节的中断也有可能导致拉流端卡顿。

因而为了反抗卡顿,一个最间接的办法就是在播放器中缓存更多数据,以期在缓存数据耗尽之前度过网络稳定。最间接的做法就是增大播放器的最大缓存,使播放器可能缓存足够多的数据。

但直播场景的特殊性在于直播内容是实时产生的,在最大缓存容许的状况下,播放器中的缓存齐全取决于以后链路上有多少缓存(还记得 GopCache 吗)。

在播放器数据生产速度不变、带宽短缺的状况下,播放器在取得了链路上所有的缓存后,buffer 长度将不再变动,也就意味着播放器只能依赖这些缓存来反抗卡顿。在能取得的缓存总量无限的状况下,进一步加强现有的缓存反抗卡顿能力的伎俩就是调整播放器生产数据的速度,例如在首帧之后判断以后水位(buffer 长度)以决定是否起播(对应起播 buffer 策略),或在水位较低时升高播放速度(对应网络自适应策略)。

在无限的带宽条件下,如果可能更无效的利用带宽、采纳更加高效的传输协定,也能够无效地反抗弱网条件下的卡顿问题。因而 KCP、QUIC、QUICU 等相较于 TCP 更加高效的协定被利用到了音视频传输当中。除此之外,在特定的带宽状况下抉择适合的码率,也是升高卡顿的无效伎俩之一,因而 ABR 也在直播中失去了利用。

实际上“卡顿”在用户反馈中涵盖的状况很多,例如:App 自身的卡顿,或者 CDN 某些操作(数据积压时抛弃视频数据造成的视频卡住、声音失常,或者在数据积压时被动使播放器报错产生重试进而导致播放器呈现鬼畜),甚至视频自身帧率较低,都会导致用户呈现“卡顿”的感觉。为了更加贴近用户对于卡顿的感触,咱们减少了视频渲染卡顿这一指标。

为什么有提早?

为了反抗卡顿,咱们须要在直播链路中减少缓存,然而缓存的引入必然导致提早的减少。

例如在抖音上线低提早 FLV 之前,端到端提早在 5~8s,而这些提早的引入次要起因就在于 CDN 边缘节点上的 GopCache – 只有缓存到足够的数据才会进行下发,在这个过程中便引入了时延(当然不论是推流端采集、服务端两头链路都会引入提早,然而绝对于缓存引入的提早影响较小)。

在客户端播放速度不变的状况下,提早会始终放弃上来,另外在产生卡顿(且未触发重试)时提早会一直累积。

因而通过调节边缘节点的 GopCache 大小能够间接影响到链路上的端到端提早。与此同时,Gop 的大小也会影响到不同用户之间的提早差,在具体场景中就体现为两个观众的提早存在差别(比方内购会他人看到主持人说了“3、2、1,开抢”,你才看到“3”),两名观众进入直播间的时间差即便很短,然而提早差可能达到一个 Gop(以下图为例,假如快启 buffer 上限为 1.3s,用户别离在 1.2s 和 1.4s 进入直播间,提早别离是多少?)。

为了更好地保障观众端的提早体验,咱们在全面梳理了线上的提早产生起因,实现了低提早 FLV 计划,使得线上端到端提早由 7s 左右降落至 3.5s 左右,并在抖音获得了显著的 QoE 正向收益;与此同时,RTM 低提早拉流计划也在稳步推动中。

如何判断拉流异样问题的产生环节?

问题定位个别流程

如前文所述,直播是一个全链路的业务状态,尤其是拉流端处在整个链路的末端,各个环节的问题都会导致拉流端出现异常。因而如何依据现有信息及工具来定位问题的本源,便是解决问题的要害。定位问题个别要经验以下过程:

  1. 对于各类问题,首先须要的是明确的 case 与信息,针对具体 case,须要的信息有:

    • 拉流端 device_id 或 user_id
    • 问题景象形容(至多提供 roomID 或者流名)
    • 问题产生工夫
    • 最好提供录屏
  2. 在 Trace 平台,依据前述信息检索相干日志,能够依据问题景象进一步查找对应的事件(对应 event_key 字段)

    • 拉不到流?找到 play_stop 事件

      • 依据 first_frame_blocked 字段判断首帧卡在哪个阶段
      • 依据 code 字段判断错误码是什么(错误码是 0?还记得拉不到流的局部起因是首帧慢吗?)
    • 首帧慢?找到 first_frame 事件

      • 依据前文中分阶段耗时对应的字段,寻找存在显著异样的阶段
    • 卡顿?找到 stall 事件

      • 依据流名查问对应工夫点推流端的推流状况,是否推流端卡顿

        • 依据拉流端在问题时间段前后的日志信息判断是持续性卡顿、短时间稳定还是流相干卡顿
        • 如果找不到 stall 事件,只有 render_stall,那么可能的起因就是产生了丢帧
  3. 例如花屏、绿屏之类的问题,在日志上个别没有特地显著的谬误,此时能够通过查看流回放判断源流是否有异样。如果源流回放没有异样,且用户播放转码流,且流曾经完结的状况下,就须要经营同学继续关注相干反馈,尽可能保留现场(因为转码流不会进行录制)。

问题范畴与定位方向

除了前述定位问题的个别过程,问题产生的范畴也是疾速定位问题的无效根据。个别有以下判断办法,依据问题(同一时间段)产生在不同用户或场景判断:

  • 所有主播及观众 –> 这种状况十分少见,如果呈现,个别意味着呈现了整个零碎级别的问题
  • 单个主播的所有观众 –> 推流端自身或推流端到边缘节点或源站引起,如果到边缘节点日志失常,个别为源站问题
  • 同一 CDN 下的多个主播的所有观众 –> 收流节点问题(收流节点雷同)或源站问题(收流节点不同)
  • 单个主播的局部观众(仅转码流观众或仅源流观众)–> 源站转码问题(默认分辨率的存在导致判断易受影响,如果只有转码流播放,那么产生问题即便的是源流,最终反馈问题的也只有转码流观众)
  • 单个主播的局部观众(某一地区)–> 散发 CDN 问题,个别是某一节点问题,层级因地区而异
  • 单个主播的局部观众(CDN 汇集)–> 散发 CDN 问题,这种状况个别呈现在流动,有多家 CDN 参加散发
  • 全量用户(或有版本等特色)某一时间点后 –> 根本是放量引起的
  • 某些版本一段时间呈现激增并骤降 –> 个别是流相干的问题,在某些版本触发了异样

问题定位的教训是须要一直积攒的,不可能欲速不达;除教训外,还须要深刻了解各个角色在整个链路中的作用,依据问题的体现揣测根因,再基于揣测进行佐证。

止损伎俩

推拉流 SDK 对于新性能都会增加各类开关,以保障性能上线后、出现异常时能够及时敞开进行止损。然而对于一些新问题或者一些历史问题,如果没有相应开关进行管制时,对于业务线会造成不同水平的影响。

这类问题个别会是流相干的,且在测试阶段隐蔽性高(测试阶段没有方法百分之百笼罩到这些流问题,尤其是新问题)、突发性强(往往随直播开播时产生、关播时完结)。这类问题在初步剖析问题、确定问题能够通过调度等伎俩解决时,能够尝试与转码、流调度配合实现这类问题的及时止损。随后在新版本进行问题修复。

总结

在理论的直播相干业务开发过程中,还有许许多多乏味且值得深刻开掘的内容,这篇文章仅仅是对直播链路做了一个简略的概览,力求帮忙没有直播开发相干教训的敌人对直播全链路有一个全局性的了解,置信各位朋友在了解了直播全链路之后,对于直播体验优化或问题排查肯定可能更加得心应手。

对于「字节跳动视频云技术团队」

字节跳动视频云技术团队,负责字节跳动旗下抖音、西瓜视频、今日头条等多个业务视频点播、视频直播、Web 多媒体等音视频技术计划建设、播放体验优化等工作,为数亿用户提供优质的音视频服务体验。

同时,团队也致力于钻研、摸索多媒体畛域的前沿技术,参加国内、国内多媒体方向的标准化工作,为多媒体内容分析、解决、压缩、传输、翻新交互等畛域提供软硬件解决方案,泛滥翻新算法曾经广泛应用在抖音、西瓜视频等产品的点播、直播、实时通信、图片等多媒体业务,并向火山引擎的企业级客户提供技术服务。

退出移动版