点播成本节省的点其实涉及诸多部分,例如:CDN、转码、存储等,而利用播放器降本却是很多客户比较陌生的部分。火山引擎基于内部支撑抖音集团相关业务的实践,播放器恰恰是成本优化中最重要和最为依赖的部分。
火山引擎的视频团队做了份数据统计,在一个很经典的视频业务中,我们在2022年至2023年大约1年半的时间里,针对这个业务进行了33次成本优化点,其中13次是播放器主导的优化,其余的有12次也是需要播放器强配合的优化,也就是说在这个业务里,75%的成本优化是直接或间接由播放器参与,可见客户端对成本优化的关键作用。
最终我们在很多实践中也发现通过播放器的优化可以为点播业务节省20%甚至更多的成本,本篇内容就将聚焦在播放器层面如何节省成本这一主题。
在视频点播的成本构成中,有很明显的二八原则:
CDN带宽成本占绝对的大头,80%都是带宽成本;
其次是存储和转码成本,二者占不到20%;
额外还有一些其他的周边的成本,比如日志处理的数据成本、AI处理的成本。
我们可以将成本的优化理解成“置换”,在点播的成本优化中,就存在2种“置换关系”:
第1种置换关系是“成本项之间的置换”,指的是「带宽-转码-存储」之间的置换。
上图是H.264升级到H.265编码格式的例子,265的压缩率相对比264要优20%-40%,所以带宽、存储上265是大幅度减少;但是265的计算复杂度要复杂很多,所以转码成本大幅度升高。
而这个图不是一个等边三角形,带宽成本要远大于转码和存储成本,所以这个置换是非常划算的。
第2种置换是“成本和体验的置换”,我们一般说是“跷跷板效应:
例如:
我们增大缓存时长,对应体验上「卡顿率」就会降低,但是成本会增加;
抖音小视频feed流场景,我们做预加载,这时候首屏感会更顺滑,但对应的成本是增加的;
降低码率,那么体验上感到清晰度变差了,而成本就是减少的;
跷跷板中间支点是技术,我们通常是希望固定体验、降低成本,依靠技术来支撑。
所以我们总在说降成本,那降的到底是什么呢?我们这里用一个很简单的乘法公式来表示:
在过去,“单价”是非常明显的因素,大家往往选择在采购环节尽量的压低单价;而“用量”上通常会被认为是无法改变的业务因素。
但“用量”实际上是包含2类,一类是正常用量,确实是比较难改变的业务因素,但另一类是“浪费”,是可以被优化的。
所以如何识别出浪费、降低浪费,是播放器降本的关键点。
那么造成浪费的因素有哪些呢?
例如在视频播放过程中,会包括“已播放的数据”,和“未播放但已经缓存的数据”,如果用户中途离开播放,那其中“已缓存的数据”都是浪费了。
所以我们定义“浪费”是“已经缓存了、但不需要的字节数”。
从理想上来说,没有浪费是最好的;但往往业务中,浪费是非常大的,大于30%是很常见的。
常见的可能带来的浪费包括了:
•未播放离开
•向后拖拽
•切换档位
•清晰度溢出(举例:很小的手机屏幕播放4K的内容,肉眼感知不到清晰度的区别)
针对上述的浪费我们进行了如下的具体优化方法:
承接上图的播放器缓存示意图,如果用户播放过程中离开了,那么深灰色是浪费部分。很容易就想到我们减少深灰色的部分的大小,比如把播放水位降低1/3(也就是图中浅黄色的部分减少掉),不去缓存,那么浪费就明显的减少了。
这个就是静态水位的思路,通过减少缓存水位来减少浪费。
但是,静态水位是很难抉择的,水位大了浪费多,但是水位太小了,卡顿就会明显的增加。
这里有个马太效应,从原理上,缓存的本质是为了对抗网络的抖动的。 网络稳定好时,只需要很少的缓存就足够了,但是网络好时缓存会填充的很快,大部分时间都是饱和的。反之,波动大的网络,需要更多的水位,但总的上限也有限,无法提供有效的缓存。
为此我们实现了的动态水位算法,我们根据一些因素来动态的决策缓存水位的大小:
•1)探测用户的网络速度和稳定性,对稳定性高、速度快的,我们减少缓存;对网络速度差、稳定性差的网络,就增大缓存,这样在网络抖动时就能够有更大的缓存空间使用;
•2)根据用户的播放行为,通过数据分析道,视频观看的前期,用户离开的比例会更高,观看的后期,离开的比例就会降低, 所以前期的缓存水位小一些,后期的缓存水位大一些;
•3)还有一些其他的因素,但目的是在每次播放时决策出一个尽量合理的缓存水位,来平衡卡顿和浪费;
决定了缓存水位大小之后,还有个细节点就是range请求。
Range是http协议的一个请求头,默认是“0-请求” ,表示请求完整文件。
左侧的图示意,如果是单独发一个“0-请求”,那么CDN服务端就会持续的返回整个文件,如果在中途断开,从服务端视角来说,这些数据已经发送过去了,无论客户端是否需要,都已经计费了,就构成了浪费。
在上图,我们分成3段来发range请求,中途断开时,是可以停止掉最后一段,那么浪费就大幅度减少了。
同样,静态的range是很难抉择的,range拆分的太细会引起卡顿的提升;range过大了成本节省的效果又不够了。
这里我们引入目标水位的概念,就是刚刚讲的动态水位算法所决策出来的水位大小。
播放器Range请求的应遵循两个原则:1. 将当前视频尽快缓存到目标水位。2. 控制Range拆分的大小,避免太小的Range拆分。
上图是动态水位算法+动态range拆分的效果示意图:
•横轴代表时间线。 纵轴上图是视频下载的大小,蓝色块代表一个range请求;下图是缓存的大小,橙色的折线表示缓存随着视频文件下载和播放时间的波动情况,横着的虚线是目标水位。
我们从左到右,分析下目标水位和range的关系:
• 看第1条竖着的红线,决策出来第一条目标水位1,是启播水位,启播时的range会略大于后面的2个range;
• 第2条竖着的红线,是判断出一次水位提升,有可能是检测到网络波动,会提高目标水位到水位2,同时做一次略大的range请求来达到目标水位;
• 第3条竖着的红线,是再次提升目标水位,到水位3,有可能是因为观看时长增加到阈值,判断离开概率较小,所以保持高水位;
•后续的播放,在目标水位3随着时间波动,range大小也会稳定些。
从最终效果上看,在任意一个时间点离开,都能够保障相对合理的浪费。
•我们在不同业务上实践了很多次动态水位+动态range的AB实验,在体验指标持平或更优的前提下,带宽降低8%;
在类似于抖音这种feed流下滑的场景,会提前加载好下面的视频,能够使滑动更顺畅,我们 叫“零首帧”效果,里面作用最大的就是预加载。
一般的预加载是固定几个视频,每个视频固定的大小。为了得到更好的预加载效果,会尽量多、尽量大的做预加载,也就构成了浪费。
我们做的“精准预加载策略”,在“时机、大小、个数”上做精细化的优化:
•1) 时机上,对预加载也进行切片,这样可以区分出来一部分是紧急的, 其他是不紧急的。比如图里,标记P0的是要最优先下载的,然后可以做预加载,预加载标记P1的部分,然后是当前视频的缓存水位,之后可以选择是否要预加载P3的部分。
•2)大小上,每个视频也会结合视频的长度、头大小、码率等因素计算出来需要预加载的大小
•3)个数上:按照feed list中的优先级依次预加载后续N个视频(动态计算),也会结合用户本身的行为(比如快速滑动)来动态决策。
•我们在不同业务上进行AB实验,都能够验证这策略可以有效的提升预加载利用率、降低对应流量成本 ;
现在的主干场景是在移动端看视频,大家都会有启播选档的策略,就是在播放启动时,决定所需要的清晰度,一般是跟随网速、码率来决策的。
经常大家面临的场景是,在竖屏里播放横屏视频时,实际上在很窄的一个空间里进行播放, 这个时候,如果依然使用完整的清晰度,那么肉眼是看不出来的清晰的。而且,通常情况下小窗播放时用户的主要关注度也并不是画面清晰度,所以就产生了实际上的清晰度浪费。
我们对应的解决策略叫 “窄屏低清” ,就是识别出来显示区域很窄时,播放低清晰度的视频(比如360P),当需要横屏时,再快速的切换为正常的清晰度。这里如果是mp4格式播放,需要转码也做些配合,支持mp4的帧对齐和平滑切换。
在很多应用中都是很常见的,也有常见的小窗播放,多个业务的AB实验都能有3%以上的成本收益;
另外清晰度上还有个很棒的能力,是客户端超分。随着客户端超分能力的优化,现在很大一部分机型在客户端向上超分一个档位是完全没问题的,耗电可以忽略。
对应节省成本的策略是“降档超分”,就是分发的清晰度向下降一档,然后再通过客户端超分降主观清晰度补回来。在国内当前的机型条件下,大部分业务能够有6~8%左右的成本收益。
我们根据「播放器日志是否可以识别」、「是否是正常流量」把流量分成了4类。
在非常多的业务中会发现第三种情况:流量有异常浪费,比如有部分视频码率过高,可能是没转码,或者转码模版用错了。我们开始时会认为“这些都是很明显的失误,业务层小心点不就行了么? ”,但后来我们做成了单独的异常流量分析模块。我们跟业务尝试分析原因,发现业务总是复杂的:
比如业务场景很复杂,包括短视频、长视频、主页视频、广告视频等等;
研发的迭代也通常会带来些历史问题;
并不是所有的人员都需要持续的感知成本,只要有一个环节漏掉了,那么就可能会造成很大浪费。
这里还有个问题点,如果是体验问题或者bug,总会有用户保障,来及时发现。但成本问题,用户基本是无法发现的,发现时就比较晚了。
我们是通过端到端的日志分析来发现和避免这些浪费的。原理很简单:
1)在客户端对日志染色,
2)cdn日志里记录的,区分是否是播放器产生的、是否是我们点播的域名。
3)对两头的日志进行比对和分析;
不仅如此,这里还有个副产物,是通过这些日志分析,识别到业务真实是被盗链了,然后做盗链的治理。
以上是火山引擎是实际业务服务过程中探索出的优化方案,但优化是不是有上限的,优化到什么水平可以达到成本和体验的平衡,更多的能力是通过数据能力持续的挖掘出来的。
先从结果上来看,我们成本优化后通常会有2个报告:
1)AB实验报告:里面会分析对QoE的体验影响多少,对成本优化的影响多少,比如人均播放时长增加多少,成本降低多少。做成本的AB实验,依赖一个工具“客户端成本指标”。
2)价值回溯文档:用于核算真实收益有多少,一般发生在完整上量之后,比如1个月或2个月后。关键结果叫“万分钟播放成本”,这个对应的依赖的工具是“成本评估公式”。
这张图从左往右是视频点播的数据流向。想要建设好成本埋点,有2个难点:
1、成本拟合。因为真实的计费数据是左侧CDN的计费日志,在右侧的客户端侧实际上是没有成本数据的,所以我们需要把数据缓存层的对成本的埋点尽量的拟合,使之尽量的对应到CDN的计费日志。这个过程是非常艰难的,我们通过了大量的离线校验。
2、提升可解释率。业务动作比较复杂(播放、预加载、拖拽、重播等等),举个例子,重复播放,播放层是记录2遍播放时长的,但是因为有缓存,真实的网络请求只有1遍。我们想要两份数据尽量对齐、可解释,就需要涵盖住尽量所有的业务场景。
我们当前达到了“可解释率达到95%”,也就是说比如服务端CDN产生了100Gbps的带宽,客户端的日志能够拟合解释清楚95%。
虽然还不到100%,但日常来做成本优化、成本归因已经足够了。
下图是成本指标进入AB实验后的结果
核心指标
归因指标
成本数据进入AB实验有什么用呢?
1、快速判断客户端的成本变化结果。大部分成本优化的能力都是伴随着策略的,不同策略有不同的结果置换关系,我们需要通过实验来确定效果。假设没有客户端的成本数据的话,我们就需要用不同的CDN域名来实验,这是很低效的,并且域名带宽的波动也会引起成本的波动。而在客户端成本指标进入了AB实验之后,大部分场景都直接看报表数字就可以了;
2、机制上可以防蜕化。 业务的产品经理、分析师等角色也日常会关注到实验数据的,当成本数据也进入实验后,这些角色也可以关注到成本的变化,这样就能够防退化了。举例:版本升级时,只要经历了AB实验,就很难有成本退化的问题。
“成本评估公式” ,本质是一种单位成本的衡量方法。
我们叫“万分钟播放成本”,分子是点播的IT成本,分母是点播视频消费时长。
从技术侧来看,分子是“CDN、存储、转码等各种成本的加和”,分子是播放的时长。
这个公式很简单,但为什么要这么做呢?
涉及到成本优化,就会跟采购、财务团队打交道,采购、财务看到的都是每月的账单,业务用量每个月都在上下波动,导致账单每个月也都在波动。万分钟播放成本是单位成本,就可以刨除掉业务用量的影响因素,来衡量成本是否真的优化了。
我们来拆解其中的万分钟CDN成本:
万分钟CDN成本的影响因子会涉及到价格、码率、浪费率、带宽流量比。
举一个真实的例子:
有个客户反馈成本增加了,但是客户自己的业务用量在波动,不太好判断是什么情况。我们拆解分析万分钟CDN成本的具体影响因子,就发现了万分钟CDN成本确实是涨了11%,主因是“码率”涨了8%,“浪费率”增加了5%。
在服务业务的过程中,大家经常会面临一个问题, 还能再降多少?极限是多少?
这些问题是很难回答的,因为每个业务的场景都不同,举例缓存浪费中,每个业务的客户中断离开的模型可能都不一样,那么建设统一的标准就很难了;
火山引擎目前通过3种方式来建设标准:
1)通过排名获取标杆:将类似场景的业务进行排名,对齐当前技术做的最好的,可以作为一种标准;
2)离线的实验来模拟:我们做了成本的自动化测试平台,设计测试case,测试出来不同的参数的成本结果是多少,最后总结分析出来极限是多少;
3)通过“理论公式”来推算“标准” :举例通过“视频播放时长、中途离开比例”的关系,然后推算出理论的优化空间有多少;
面对的业务越来越多,降本的能力也越来越多时,就会遇到效率问题:功能这么多,应该用哪些?每个业务的场景也不一样,那么策略参数应该怎么配置呢?
万分钟播放成本分析和策略推荐
解决方法是做顾问:上图是我们的一个万分钟CDN成本与理想万分钟成本的一个差异分析表,我们给计算出了对应的差异,然后再给出可以补足差异的策略或功能推荐。
当然,这个表只是一个总结概览,更多的内容我们会整理成“顾问服务报告”,把各个点的差异、业务分析、解决方法与业务逐一的讨论分析。
万分钟播放成本是一个非常简单、容易落地、价值很大的工具,大家计算下万分钟播放成本,如有调优的诉求,非常欢迎来与火山引擎交流。火山引擎视频点播https://www.volcengine.com/product/vod。