布景
视频缓存已经成为各大视频App
的标配,而且从功能运用数据来看,每个月运用的量都很大。所以,做好缓存功能的优化,对进步用户体会有十分重要的作用。
搜狐视频iOS
端的缓存和爱奇艺的有区别,并没有多个视频一起缓存的产品功能,而且缓存分片是串行下载的。即m3u8
文件缓存下来后,次序下载ts
地址对应的文件,导致网络运用率不高。
为了进步用户体会,进步缓存速度,我对缓存进行了速度优化,进步了网络运用率。详细计划如下。
计划规划
分析
缓存计划的中心在于,最大程度的进步网络运用率。但并非单纯的扩大并发缓存数量,这样会导致设备发烫、网络资源争夺等许多问题。应该依据网速和设备功能等要素,动态决议分片数量。所以,规划一套合理的测速计划,以及缓存计划就十分重要。
因为咱们的网络运用的quic
协议,所以在网络层面已经没有太大的进步空间,只能通过上层进行优化。
缓存计划
假如是新建的缓存使命,没有测速数据或数据已过期。数据已过期指的是两次缓存不是接连的,例如暂停后再继续缓存,或重启后缓存。则依据网络环境做判别,来决议并行下载数量。流量环境并行数量为2,WiFi并行数量为4。这个值是测验的一个经验值。
并发数量并不是固定的,从第一次下载开端,每次缓存的过程都会进行测速,并依据测速成果动态修正并发数量,而且继续运用缓存的速度数据进行测速,来修正并发数量。当网络环境产生改动后,这时分需求重新进行测速,从第一步重新开端。
在网络的部分,底层quic
运用的cronet
库作为完成。cronet
没有长连接的概念,是通过cronet
线程处理的并发,同一端口最多6条线程,最多不超过16条线程。所以,需求上层逻辑控制并发数,并不能直接设置并发数。
因为项目中大多数的视频都是m3u8
格式,缓存加快只对m3u8
的视频缓存做了加快,drm
和mp4
格式的视频并没做处理。而且,drm
和mp4
目前是流式下载,假如想加快需求后端对视频文件做切片。
测速计划
测速需求考虑下面几个中心要素。
- 网络环境,
WiFi
和流量的均匀网速相差比较大,WiFi
下能够更充沛的运用网络资源。 - 网速,最中心的要素,网速慢的话,什么计划都没用。
- 设备功能,相同的网速,在不同设备上表现可能不一样。低版别设备并发数太多,可能会导致卡顿或发热严峻。
- 视频类型,电影单个剧集
ts
数量较多,缓存时间长且连接,所以能够恰当添加并发数。
并发数需求控制在一个合理的区间,假如下载并发数太多,会形成恳求拥堵,然后触发timeout
。假如下载并发数过少,会导致网络运用率不高。
而且,不只需考虑缓存部分,还需求考虑是否会争夺其他恳求的资源。否则会导致其他非缓存的恳求,因为缓存占用带宽过多,导致恳求变慢或许多触发timeout
。
测速计划通过实践验证,依据上述要素设置不同的权值。在考虑要素的过程中,还需求避免手机发烫的问题,所以需求屡次测验才能决议权值。计划的中心在于,最大极限的运用用户的带宽,以及设备功能,而且和发热坚持一个杰出的平衡。温度适中,而且不会影响fps
。
下图是整个缓存计划的一个流程图,看图比较直观。

测验数据
测验办法
因为还未上线,所以数据来源于控制台日志,但通过屡次以及不同网络环境下的测验。缓存类型为电影和电视剧,表格中前两列为电影,后两列为电视剧。
测验办法,在同一时间缓存同一剧集,相同清晰度,比照线上版别和缓存加快版别的不同,分别测验WiFi和流量环境。在测验阶段,设备一直在前台。
从数据来看,电影因为文件比较大,在网速快的状况下进步比较显着。电视剧因为网速刚上来就下载完了,数据没有这么显着,但也有50%
左右的进步。
一起对下半年缓存数据进行了下统计分析,流量环境下的缓存的只占二十分之一左右,能够看出WiFi
环境下是占绝大多数的。所以,WiFi
环境下加快,能够更好的让用户享受到缓存加快带来的优化体会。
鉴于运用缓存功能的用户,大多数都是在WiFi
环境下运用,所以主要还是以WiFi
的数据为准。WiFi
环境分别测验了公司WiFi
,和我家里的WiFi
,能够代表许多WiFi
网络环境了。下面是不同网络环境下,屡次测验的均匀成果。
WiFi
通过屡次测验,均匀提速为2.35
倍。

流量
通过屡次测验,均匀提速为1.50
倍。

播映流畅性
为了避免缓存争夺过多网络资源,然后影响播映的流畅性,对WiFi
和流量环境下,缓存电视剧和电影进行了测验。测验成果表明,不同网络环境下缓存电视剧和电影,不会对播映流畅性形成影响,播映视频一直在60
的fps
。
代码完成
下面是完成的中心逻辑的伪代码,主要为了表现测速的代码流程。
/// 核算当时并发数量,一切缓存使命用一个值,当网络产生变化或许重新开端时,运用默认值
/// 下面核算中心准则在于,最大程度运用真实带宽
- (void)calculateDownloadSpeedWithTask:(SVDownloadTask *)downloadTask {
/// 依据网速设置并发下载数量,网速单位判别为:mb/s
CGFloat currentSpeed = downloadTask.downloadingSpeed / 1024.f / 1024.f;
NSInteger maxConcurrentCount = 4.f;
/// 以电视剧为例,一个ts大小在1MB~2MB之间,也有少部分在这个区间之外,比例20%左右
/// ts文件一半以上都在1MB~1.5MB之间,并发数和网速并不是直接关系的,中心在于进步网络运用率,真正能用到多少网速
if (currentSpeed > 0.f) {
/// 网速在1MB以下的状况在流量环境下是很常见的
/// 阈值的区间设定应当遵从泊松散布,越小的部分越细
if (currentSpeed < 0.5f) {
maxConcurrentCount = 2;
}
else if (currentSpeed >= 0.5f && currentSpeed <= 1.f) {
maxConcurrentCount = 4;
}
else if (currentSpeed >= 1.f && currentSpeed <= 2.f) {
maxConcurrentCount = 5;
}
else if (currentSpeed >= 2.f && currentSpeed <= 3.f) {
maxConcurrentCount = 6;
}
else if (currentSpeed >= 3.f && currentSpeed <= 4.f) {
maxConcurrentCount = 7;
}
else if (currentSpeed >= 4.f && currentSpeed <= 5.f) {
maxConcurrentCount = 8;
}
else if (currentSpeed >= 5.f && currentSpeed <= 7.f) {
maxConcurrentCount = 10;
}
else if (currentSpeed >= 7.f && currentSpeed <= 10.f) {
maxConcurrentCount = 12;
}
else if (currentSpeed >= 10.f && currentSpeed <= 12.f) {
maxConcurrentCount = 16;
}
else if (currentSpeed >= 12.f && currentSpeed <= 16.f) {
maxConcurrentCount = 18;
}
else if (currentSpeed >= 16.f) {
maxConcurrentCount = 20;
}
NSInteger dataType = downloadTask.dataType;
/// 假如在视频刚下载的时分,网速核算可能会低于实践网速,所以在前期阶段能够恰当添加并发数,后期不适用
if (downloadTask.downloadSuccessCount < 6 && currentSpeed > 0.3f) {
maxConcurrentCount += 2;
}
/// 假如是电影,缓存继续时间长,能够在网速允许的状况下恰当添加并发数
else if (dataType == videoFeeFilm && currentSpeed > 1.f) {
maxConcurrentCount += 2;
}
}
/// 功能检测计划1:
/// 依据不同设备创立一个映射表,依据设备型号考虑是否对并发数进行降级。但这个计划并不合适,因为需求保护一个远端的映射表。
/// 功能检测计划2:
/// 依据当时cpu和运转内存的运用状况,进行对应的降级战略,这种计划比较通用,不需求保护映射表,而且能够实时反映出硬件的运用状况。
CGFloat cpuUsage = [UIApplication sharedApplication].cpuUsage;
int64_t memoryActive = [UIDevice currentDevice].memoryActive / 1024 / 1024;
CGFloat batteryLevel = [UIDevice currentDevice].batteryLevel;
/// cpu的取值规模是0.f ~ 1.f,假如是1.f则表明100%,但cpu经常会超频,在测验过程中短时间的超频是很常见的,170%的超频都是有的
/// 发现即使到1.f界面也不会产生卡顿,假如产生超频,就对缓存进行降速
if (cpuUsage > 1.f && maxConcurrentCount > 4) {
maxConcurrentCount -= 2;
}
/// 可用运转内存等于-1,表明获取有问题
else if (memoryActive == -1) {
/// nothing
}
/// 可用内存小于100MB,对并发缓存数量进行约束
else if (memoryActive <= 100.f && maxConcurrentCount > 4) {
maxConcurrentCount -= 2;
}
/// 可用电量等于-1,表明电量获取有问题
else if (batteryLevel == -1) {
/// nothing
}
/// 电量抵达临界值,对并发缓存数量进行约束,避免呈现卡顿
else if (batteryLevel <= 0.02f) {
maxConcurrentCount -= 2;
}
/// 极点状况下的兜底战略
if (maxConcurrentCount < 2) {
maxConcurrentCount = 2;
}
/// 最后再设置并发值,避免一个办法里赋值屡次
self.maxConcurrentDownload = maxConcurrentCount;
}
收益
缓存速度进步
缓存加快的效果十分显着,咱们先来看下加快前和加快后的视频比照,网络环境用的是家里的WiFi
。我们能够看到加快前的均匀速度为4.32 mb/s
,加快后的均匀速度为14.96 mb/s
,加快后的效果十分显着的。
因为网络运用率的进步,缓存加快在WiFi
环境下更为显着,WiFi
网速快的状况下,甚至能够达到20+mb/s
的下载速度。
额外收益
在开发缓存加快的过程中,也顺带解决了许多其他问题。
- 整体整理代码逻辑,添加注释
500+
行,添加日志50+
条。有助于后期代码保护,以及排查线上问题。 - 通过整理代码,发现一些线上
bug
。例如:封闭开关后,应该弹窗翻开体系网络弹窗,而且跳转体系设置页面。线上反应是弹出“翻开搜狐视频使用内的流量弹窗”,点击后开端缓存,网都没有无法缓存。